精华内容
下载资源
问答
  • 数据结构之集合

    千次阅读 2020-09-08 22:57:44
    数据结构之集合

    数据结构之集合

    展开全文
  • 数据结构之集合详解

    2019-04-05 15:05:47
    数据结构之集合详解集合(set)一个以二分搜索树为底层实现的集合一个以链表为底层实现的集合集合的时间复杂度分析唯一摩尔斯密码词 LeetCode804号问题有序集合和无序集合多重集合 集合(set) 回忆我们之前实现的...

    集合(set)

    • 回忆我们之前实现的二分搜索树,它是不能存放重复元素的,它本身就是非常好的实现“集合”的底层数据结构

    Set<E>

    • void add(E) 不能添加重复元素 典型应用:客户统计、词汇量统计
    • void remove(E)
    • boolean contains(E)
    • int getSize()
    • boolean isEmpty()

    首先我们定义了一个set接口

    public interface Set<E> {
    
        void add(E e);
        boolean contains(E e);
        void remove(E e);
        int getSize();
        boolean isEmpty();
    }
    

    一个以二分搜索树为底层实现的集合

    import java.util.ArrayList;
    
    public class BSTSet<E extends Comparable<E>> implements Set<E> {
    
        private BST<E> bst;
    
        public BSTSet(){
            bst = new BST<>();
        }
    
        @Override
        public int getSize(){
            return bst.size();
        }
    
        @Override
        public boolean isEmpty(){
            return bst.isEmpty();
        }
    
        @Override
        public void add(E e){
            bst.add(e);
        }
    
        @Override
        public boolean contains(E e){
            return bst.contains(e);
        }
    
        @Override
        public void remove(E e){
            bst.remove(e);
        }
    }
    

    一个以链表为底层实现的集合

    import java.util.ArrayList;
    
    public class LinkedListSet<E> implements Set<E> {
    
        private LinkedList<E> list;
    
        public LinkedListSet(){
            list = new LinkedList<>();
        }
    
        @Override
        public int getSize(){
            return list.getSize();
        }
    
        @Override
        public boolean isEmpty(){
            return list.isEmpty();
        }
    
        @Override
        public void add(E e){
            if(!list.contains(e))
                list.addFirst(e);
        }
    
        @Override
        public boolean contains(E e){
            return list.contains(e);
        }
    
        @Override
        public void remove(E e){
            list.removeElement(e);
        }
    }
    

    集合的时间复杂度分析

    在这里插入图片描述
    h为二分搜索树的高度,考虑特殊情况下高度h会等于n,使用平衡二叉树可以解决这个问题。

    唯一摩尔斯密码词 LeetCode804号问题

    问题链接:https://leetcode-cn.com/problems/unique-morse-code-words/

    解答代码

    import java.util.TreeSet;
    
    /**
     * Created by binzhang on 2019/4/5.
     */
    class Solution {
        public int uniqueMorseRepresentations(String[] words) {
    
            String[] codes = {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
    
            TreeSet<String> set = new TreeSet<>();
            for (String word : words){
    
                StringBuilder res = new StringBuilder();
                for (int i = 0 ; i < word.length() ; i ++)
                    res.append(codes[word.charAt(i) - 'a']);
    
                set.add(res.toString());
            }
    
            return set.size();
        }
    }
    

    有序集合和无序集合

    • 有序集合的元素具有顺序性 基于搜索树的实现
    • 无序集合中的元素没有顺序性 基于哈希表的实现(比搜索树更快)

    多重集合

    • 集合中的元素可以重复
    展开全文
  • 数据结构之集合Set

    2020-03-27 12:01:31
    1、高层的数据结构集合Set和映射Map,什么是高层的数据结构呢,比如说是栈和队列,这种数据结构更像是先定义好了使用接口,有了这些使用接口,包括数据结构本身所维持的一些性质,可以很方便的放入到一些应用中,...

    1、高层的数据结构,集合Set和映射Map,什么是高层的数据结构呢,比如说是栈和队列,这种数据结构更像是先定义好了使用接口,有了这些使用接口,包括数据结构本身所维持的一些性质,可以很方便的放入到一些应用中,但是底层实现可以多种多样的,比如栈和队列,底层实现既可以是动态数据,也可以是链表。

      集合就是承载元素的容器,集合Set中有一个重要的特性,就是每个元素在集合中只能存在一次,可以快速帮助去重工作,去重就是去除重复的元素,让所有的元素只保留一份。

    2、基于二分搜索树实现的Set集合。代码,如下所示:

    首先定义一个接口,然后分别使用二分搜索树的方式和链表的方式实现集合的功能。

     1 package com.set;
     2 
     3 /**
     4  * @ProjectName: dataConstruct
     5  * @Package: com.set
     6  * @ClassName: Set
     7  * @Author: biehl
     8  * @Description: ${description}
     9  * @Date: 2020/3/14 10:41
    10  * @Version: 1.0
    11  */
    12 public interface Set<E> {
    13 
    14 
    15     /**
    16      * Set集合的新增
    17      *
    18      * @param e
    19      */
    20     public void add(E e);
    21 
    22     /**
    23      * 删除集合的元素
    24      *
    25      * @param e
    26      */
    27     public void remove(E e);
    28 
    29     /**
    30      * 判断是否包含某个元素
    31      *
    32      * @param e
    33      * @return
    34      */
    35     public boolean contains(E e);
    36 
    37     /**
    38      * 获取集合的个数
    39      *
    40      * @return
    41      */
    42     public int getSize();
    43 
    44     /**
    45      * 判断集合是否为空
    46      *
    47      * @return
    48      */
    49     public boolean isEmpty();
    50 }

    使用二分搜索树的方式实现,代码如下所示:

     1 package com.set;
     2 
     3 import com.tree.BinarySearchTree;
     4 
     5 /**
     6  * 基于二分搜索树实现的Set集合
     7  *
     8  * @ProjectName: dataConstruct
     9  * @Package: com.set
    10  * @ClassName: BSTSet
    11  * @Author: biehl
    12  * @Description: ${description}
    13  * @Date: 2020/3/14 10:44
    14  * @Version: 1.0
    15  */
    16 public class BSTSet<E extends Comparable<E>> implements Set<E> {
    17 
    18     // 定义二分搜索树
    19     private BinarySearchTree<E> binarySearchTree;
    20 
    21     /**
    22      *
    23      */
    24     public BSTSet() {
    25         // 无参构造函数,创建二分搜索树对象
    26         binarySearchTree = new BinarySearchTree<E>();
    27     }
    28 
    29     @Override
    30     public void add(E e) {
    31         // 对于重复的元素,不进行任何操作
    32         binarySearchTree.add(e);
    33     }
    34 
    35     @Override
    36     public void remove(E e) {
    37         binarySearchTree.remove(e);
    38     }
    39 
    40     @Override
    41     public boolean contains(E e) {
    42         return binarySearchTree.contains(e);
    43     }
    44 
    45     @Override
    46     public int getSize() {
    47         return binarySearchTree.size();
    48     }
    49 
    50     @Override
    51     public boolean isEmpty() {
    52         return binarySearchTree.isEmpty();
    53     }
    54 
    55     public static void main(String[] args) {
    56         BSTSet<String> bstSet = new BSTSet<String>();
    57         // 集合Set的新增操作
    58         for (int i = 0; i < 100; i++) {
    59             bstSet.add(i + "");
    60         }
    61 
    62         for (int i = 0; i < bstSet.getSize(); i++) {
    63             System.out.println(bstSet.toString());
    64         }
    65 
    66         // 集合Set的删除操作
    67         bstSet.remove(0 + "");
    68 
    69         // 集合Set的是否包含某个元素
    70         boolean contains = bstSet.contains(0 + "");
    71         System.out.println(contains);
    72 
    73         // 集合Set的大小
    74         System.out.println(bstSet.getSize());
    75 
    76         // 判断集合Set是否为空
    77         System.out.println(bstSet.isEmpty());
    78     }
    79 
    80 }

    3、二分搜索树和链表都是属于动态数据结构。二分搜索树和链表的数据都是存储到Node节点中的。

     1 package com.set;
     2 
     3 import com.linkedlist.LinkedList;
     4 
     5 /**
     6  * @ProjectName: dataConstruct
     7  * @Package: com.set
     8  * @ClassName: LinkedListSet
     9  * @Author: biehl
    10  * @Description: ${description}
    11  * @Date: 2020/3/14 11:54
    12  * @Version: 1.0
    13  */
    14 public class LinkedListSet<E> implements Set<E> {
    15 
    16     private LinkedList<E> linkedList;
    17 
    18     /**
    19      * 无参构造函数,对linkedList进行初始化
    20      */
    21     public LinkedListSet() {
    22         linkedList = new LinkedList<E>();
    23     }
    24 
    25     @Override
    26     public void add(E e) {
    27         // 避免将重复的元素添加进去
    28         if (!linkedList.contains(e)) {
    29             linkedList.addFirst(e);
    30         }
    31     }
    32 
    33     @Override
    34     public void remove(E e) {
    35         linkedList.removeElement(e);
    36     }
    37 
    38     @Override
    39     public boolean contains(E e) {
    40         return linkedList.contains(e);
    41     }
    42 
    43     @Override
    44     public int getSize() {
    45         return linkedList.getSize();
    46     }
    47 
    48     @Override
    49     public boolean isEmpty() {
    50         return linkedList.isEmpty();
    51     }
    52 
    53     public static void main(String[] args) {
    54         LinkedListSet<Integer> linkedListSet = new LinkedListSet<Integer>();
    55         // 基于链表实现的集合的新增
    56         for (int i = 0; i < 100; i++) {
    57             linkedListSet.add(i);
    58         }
    59 
    60         // 集合Set的删除操作
    61         linkedListSet.remove(0);
    62 
    63         // 集合Set的是否包含某个元素
    64         boolean contains = linkedListSet.contains(0);
    65         System.out.println(contains);
    66 
    67         // 集合Set的大小
    68         System.out.println(linkedListSet.getSize());
    69 
    70         // 判断集合Set是否为空
    71         System.out.println(linkedListSet.isEmpty());
    72 
    73     }
    74 }

    4、基于链表的集合实现的性能,慢与基于二分搜索树的集合实现。

    集合Set的时间复杂度分析。

      1)、增加add。
        方式一,基于链表实现的LinkedListSet,本来在链表中添加一个元素时间复杂度是O(1)的,但是对于集合Set来说,需要去除重复元素,所以对于链表需要先查询一遍,查询的时间复杂度O(1),所以整体上,基于LinkedListSet方式实现的的新增操作,时间复杂度是O(1)。
        方式二,基于二分搜索树的实现的BSTSet,新增操作,每次新增都可以排除一半元素,因为大于根节点去右子树,小于根节点去左子树,新增操作从根节点向叶子节点出发,一层一层的向下走,经历的节点是二分搜索树的深度,新增操作、查询元素、删除元素都是这个思路,那么平均时间复杂度的是O(h)或者O(logn),其中h是二分搜索树的深度。最差的效果是时间复杂度的是O(n)。解决这个问题可以使用平衡二叉树。

      2)、查询contails。
        方式一,基于链表实现的LinkedListSet,查询操作的时间复杂度是O(1),因为要把所有的元素遍历。
        方式二,基于二分搜索树的实现的BSTSet,那么平均时间复杂度的是O(h)或者O(logn),其中h是二分搜索树的深度。最差的效果是时间复杂度的是O(n)。解决这个问题可以使用平衡二叉树。

      3)、删除remove。
        方式一,基于链表实现的LinkedListSet,删除操作的时间复杂度是O(1),因为需要先找到待删除元素的前面哪一个节点,再将这个元素删除。
        方式二,基于二分搜索树的实现的BSTSet,那么平均时间复杂度的是O(h)或者O(logn),其中h是二分搜索树的深度。最差的效果是时间复杂度的是O(n)。解决这个问题可以使用平衡二叉树。
      总结,那么n和h的比较是怎么样的呢,对于一棵满二叉树来说,如果一共有h层的话,节点个数一共是2的h次方减一个节点。那么2^h-1 = n,则h = log2(n + 1),log以2为底的n + 1的对数。h = O(logn),此时不管以那个数字为底的,直接简写成h = O(logn)。

     

    展开全文
  • Redis数据结构之集合对象Redis对象集合对象intset编码hashtable编码 Redis对象 在了解Redis数据结构的时候我们会学习到简单动态字符串,压缩链表等。 但Redis并没有直接使用这些数据结构来实现键值对数据库,而是...

    Redis对象

    在了解Redis数据结构的时候我们会学习到简单动态字符串,压缩链表等。
    但Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象。Redis使用对象表示键和值,每次新建一个键值对时,我们就创建了两个对象。

    集合对象

    intset编码

    创建一个intset编码的集合对象

    127.0.0.1:6379> sadd nums 1 2 3 5
    (integer) 4
    127.0.0.1:6379> 
    127.0.0.1:6379> type nums
    set
    127.0.0.1:6379> object encoding nums
    "intset"
    

    所有元素都被直接包含在一个整数集合里

    在这里插入图片描述

    hashtable编码

    当传入字符时,变为hashtable编码

    127.0.0.1:6379> sadd nums "hello"
    (integer) 1
    127.0.0.1:6379> object encoding nums
    "hashtable"
    

    hashtable编码的集合对象底层由字典实现。字典的键就是集合的内容,值为null。

    在这里插入图片描述
    Redis字典的底层实现

    redis字典所使用的hash表结构

    typedef struct dictht {    
    	// 哈希表数组    
    	dictEntry **table;    
    	// 哈希表大小    
    	unsigned long size;    
    	//哈希表大小掩码,用于计算索引值    
    	//总是等于size-1    
    	unsigned long sizemask;    
    	// 该哈希表已有节点的数量    
    	unsigned long used;
    } dictht;
    

    table属性是一个数组,数组中的每个元素都是一个指向dictEntry结构的指针,每个dictEntry结构保存着一个键值对。size属性记录了哈希表的大小,也即是table数组的大小,而used属性则记录了哈希表目前已有节点(键值对)的数量。sizemask属性的值总是等于size-1,这个属性和哈希值一起决定一个键应该被放到table数组的哪个索引上面。

    一个空的hash表

    在这里插入图片描述

    dictEntry*[4]是一个数组,数组里的每一元素都指向一个dictEntry结构,dictEntry包含3个属性,key,value,发生散列冲突时指向下一个节点的指针next。结构如下,看得出是使用链地址法解决散列冲突。

    在这里插入图片描述
    redis的字典是通过hash表来实现的

    redis字典结构

    typedef struct dict {    
    	// 类型特定函数    
    	dictType *type;    
    	// 私有数据    
    	void *privdata;   
    	// 哈希表    
    	dictht ht[2];    
    	// rehash索引    
    	//当rehash不在进行时,值为-1    
    	in trehashidx; 
    	/* rehashing not in progress if rehashidx == -1 */
    	} dict;
    

    type属性和privdata属性是针对不同类型的键值对,为创建多态字典而设置的:·type属性是一个指向dictType结构的指针,每个dictType结构保存了一簇用于操作特定类型键值对的函数,Redis会为用途不同的字典设置不同的类型特定函数。·而privdata属性则保存了需要传给那些类型特定函数的可选参数。

    而redis字典保存两个hash表,当我们新建一个redis字典时,默认使用ht[0] hash表,结构如下

    在这里插入图片描述
    redis字典为什么要维护两个hash表?

    redis字典为了控制创建的hash表的空间开销,redis会动态调整hash表的空间大小,当ht[0]的长度满了,这里的ht[0]满了并不是指dictEntry数组里面每一个元素都存储了一个dictEntry,而是dictht的used和size相同,可能有部分dictEntry会发生散列冲突的。
    此时再向字典添加元素,此时redis字典就会进行扩容。
    首先对ht[1进行扩容,扩容的大小为比当前当前容量大的2的n次方,目标大小必须为2的n次方,这样系统进行内存分配的效率才有保证,比如当前容量ht[0]的容量为4,那么扩容的大小就应该为2的3次方也就是8.再将ht[0]的内容迁移到ht[1]此时redis字典的结构如下
    在这里插入图片描述
    这样就可以减少hash表的内存占用,不够的时候就扩容hash表。这种方法虽然节约了内存,但如果hash表已经很长了的时候,此时再扩容它的内存再分配的规模可能就会很大,造成性能影响。因此,为了避免rehash对服务器性能造成影响,服务器不是一次性将ht[0]里面的所有键值对全部rehash到ht[1],而是分多次、渐进式地将ht[0]里面的键值对慢慢地rehash到ht[1]。
    以下是哈希表渐进式rehash的详细步骤:
    1)为ht[1]分配空间,让字典同时持有ht[0]和ht[1]两个哈希表。
    2)在字典中维持一个索引计数器变量rehashidx,并将它的值设置为0,表示rehash工作正式开始。
    3)在rehash进行期间,每次对字典执行添加、删除、查找或者更新操作时,程序除了执行指定的操作以外,还会顺带将ht[0]哈希表在rehashidx索引上的所有键值对rehash到ht[1],当rehash工作完成之后,程序将rehashidx属性的加一。
    4)随着字典操作的不断执行,最终在某个时间点上,ht[0]的所有键值对都会被rehash至ht[1],这时程序将rehashidx属性的值设为-1,表示rehash操作已完成。

    集合的相关命令

    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • JAVA数据结构之集合

    2016-08-30 21:06:57
    JAVA数据结构之集合 1、集合概述 java语法中的集合,又称为容器,它是一个对象,专门用来管理一组其他对象。集合可以用来存储、检索、操作和统计一组其他对象。在集合内的对象称之为元素。在javaSE API中的java.util...
  • Python数据结构之集合概览集合(collection),正如其名称所示,是可以作为概念性的单位来处理的一组零个或多个项。几乎软件的每一个重要部分都涉及集合的使用。尽管我们在计算机科学中所学的一些内容已经随着技术的...
  • 数据结构之集合框架

    2014-03-27 21:18:21
    数据结构是数据及其相互之间的联系(逻辑关系),通常概括为集合结构,线性结构,树形结构,图型结构。  通常采用二元组表示:B=(K,R),B为一种数据结构,它由数据元素的集合K和K上二元关系的集合R所组成。当中:  K...
  • redis数据结构之集合

    2021-01-30 18:49:51
    。。。
  • Redis数据结构之集合

    2018-09-30 16:22:04
    集合有增删改查的操作,还有求集合间的交集、并集、差集等 常用命令介绍 命令 命令描述 sadd key element [element...] 添加元素 srem key element [element...] 删除元素 scard key 计算元素个数 ...
  • python数据结构之集合

    2017-08-30 21:25:21
    集合set思维导图: 集合的引入: python的set和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素. 集合对象还支持union(并), intersection(交), difference(差)和sysmmetric difference...
  • 集合set是一种包含不同元素的数据结构集合中的元素成为成员。集合的两个最重要特性是:集合中的成员是无序的;集合中不允许相同成员存在 计算机中的集合与数学中集合的概念相同,不包含任何成员的集合称为空集;...
  • Java 数据结构之集合

    2019-07-30 19:49:28
  • 底层数据结构 线性结构 线性表是一种线性结构,它是由零个或多个数据元素构成的有限序列。线性表的特征是在一个序列中,除了头尾元素,每个元素都有且只有一个直接前驱,有且只有一个直接后继,而序列头元素没有直接...
  • Java开发中 , 往往由于需要保存的对象的数目是不确定的 , 此时一般的数组便不够用了 , 为了保存这些数量不确定的数据 , Java封装了一些特殊的类, 也是我们今天的主角 , 叫做 集合类 . 它们可以存储任意类型且程度可...
  • 从数学上我们已经了解到集合的基本概念,集合是由一组无序且唯一的元素组成。可以把集合想象成一个既没有重复元素,也没有顺序的数组。
  • C++为我们提供了集合这个内置的数据结构,它是基于二叉搜索树来实现的,并且对树进行了平衡处理,使得元素在树中分布较为均匀。因此,能保证它搜索、插入、删除操作的时间复杂度为O(logn) set是stl的内置数据结构,...
  • 本文实例讲述了JS中的算法与数据结构之集合(Set)。分享给大家供大家参考,具体如下: 集合(Set) 同数学中所学的一样,集合(Set)是由一组无序但彼此之间又有一定关系性的成员构成,每个成员在集合中只能出现一次,...
  • Python数据结构之集合Set

    千次阅读 2017-07-02 11:01:05
    python中的Set()数据结构具有的一个特殊属性就是Set()中不存在重复元素 1、集合定义 a=set() 2、向Set中添加元素 a = set([1,2,3,4]) ##用add a.add(5) ##用或运算符号 a |= {6}##Set还有个update函数,可以接受多组...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,486
精华内容 4,994
关键字:

数据结构之集合结构

数据结构 订阅