数据结构与算法(九)Set集合和BinarySearchTree的时间复杂度分析

编程入门 行业动态 更新时间:2024-10-23 09:39:29

数据结构与算法(九)Set集合和BinarySearchTree的时间<a href=https://www.elefans.com/category/jswz/34/1767520.html style=复杂度分析"/>

数据结构与算法(九)Set集合和BinarySearchTree的时间复杂度分析

本文主要包括以下内容:

  1. Set集合的基本概念
  2. Set集合的基本操作
  3. Set集合的BST实现和LinkedList实现
  4. Set集合两种实现方式的时间复杂度分析

Set集合的基本概念

Set集合是对数学中集合的抽象,Set集合有两个特性:

  1. Set集合里没有重复元素
  2. Set集合是无序集合

Set集合的基本操作

  1. 插入
  2. 删除
  3. Set是否为空
  4. Set是否包含某个元素
  5. Set元素个数

可以将以上几个操作定义一下几个方法

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

Set集合的BST实现和链表实现

Set集合底层我们可以使用顺序的线性表、链表、二叉树来实现。下面分别使用二分搜索树和链表来实现下Set集合

二分搜索树实现Set

二分搜索树实现Set使用到了前面介绍的二分搜索树的实现类 BST.java

关于二分搜索树,有需要的可以查看 数据结构与算法(八)二分搜索树(Binary Search Tree)

public class BSTSet<T extends Comparable<T>> implements Set<T> {private BST<T> bst;public BSTSet() {bst = new BST<>();}@Overridepublic void add(T e) {bst.add(e);}@Overridepublic boolean contains(T e) {return bst.contains(e);}@Overridepublic void remove(T e) {bst.contains(e);}@Overridepublic boolean isEmpty() {return bst.isEmpty();}@Overridepublic int size() {return bst.size();}
}

链表实现Set

下面链表实现的Set,使用到了以前介绍的链表实现类 LinkedList.java

关于链表的内容,有需要的可以查看 数据结构与算法(二)线性表之链式存储和LinkedList

public class LinkedListSet<T> implements Set<T> {private LinkedList<T> linkedList;public LinkedListSet() {linkedList = new LinkedList<>();}@Overridepublic void add(T e) {if (!linkedList.contains(e)) {linkedList.addFirst(e);}}@Overridepublic boolean contains(T e) {return linkedList.contains(e);}@Overridepublic void remove(T e) {linkedList.remove(e);}@Overridepublic boolean isEmpty() {return linkedList.isEmpty();}@Overridepublic int size() {return linkedList.size();}
}

利用Set的特性:不允许元素重复。我们可以使用Set集合来统计下两本英文原著双城记(A Tale of Two Cities)和傲慢与偏见(Pride and Prejudice)的词汇量

Pride and PrejudiceTotal words: 125901Total different words: 6530A Tale of Two CitiesTotal words: 141489Total different words: 9944

从上面的数据可以看出,傲慢与偏见词汇量6530,双城记为9944,。这个统计只是简单的统计,比如单词的时态,单复数等都当做一个新单词。

两种实现方式的时间复杂度分析

我们来对比下基于二分搜索树和链表来实现的Set和的性能差异:

pride-and-prejudice.txtTotal words: 125901Total different words: 6530pride-and-prejudice.txtTotal words: 125901Total different words: 6530BSTSet        Time: 0.121546597
LinkedListSet Time: 2.122136759

根据上面的统计数据可以看出,BSTSet比LinkedListSet快20倍左右。

我们知道链表的插入操作的时间复杂度是O(1),但是实现Set集合需要先判断集合中是否存在(contains),所以总的下来插入的操作为O(n)

那么二分搜索树的插入时间复杂度呢? 假如我们往以下一个二分搜索树插入元素 7,插入路径如下图所示:

根据插入路径我们知道,插入元素7,只要和856作比较,不需要和链表一样最坏的情况需要和每个元素进行比较。而这个路径也就是二分搜索树的高度。下面用一个表格来对比二分搜索树实现的Set和链表实现的Set的时间复杂度:

操作LinkedListSetBSTSet
addO(n)O(h)
containsO(n)O(h)
removeO(n)O(h)

h就是二分搜索树的高度,那么高度 h 和二分搜索树节点数 n 的关系是什么呢?

分析下满的二叉树的情况就知道了节点数量和二叉树高度的的关系了。

层数该层的节点数
0层1
1层2
2层4
3层8
4层16
h-1层2^(h-1)

那么一个h层的满二叉树总共有多少节点呢?就是每层的元素个数相加:

n = 20+21+23+24+…+2^(h-1) = 2^h - 1

用对数表示就是:h = log(n+1)

用大O表示法就是: O(h) = O(log n)

操作LinkedListSetBSTSet
addO(n)O(log n)
containsO(n)O(log n)
removeO(n)O(log n)

对比下 log(n)n 的差距

nlog(n)差距
1644 倍
102410100倍
100w205w倍

这也就是为什么上面的的BSTSet和LinkedListSet快那么多的原因。

我们上面对于二分搜索树的分析是基于满二叉树的,也就是最好的情况下,但是我们知道二分搜索树在最坏的情况会退化成链表,这就需要用到平衡二叉树如 AVL树红黑树,就算是最坏的情况也能保证二分搜索树的不会退化成链表,保持树大致的平衡,后面会介绍到平衡二叉树相关的内容。

Reference

本文主要内容和大纲是学习了慕课网 liuyubobobo 老师的视频《算法大神带你玩转数据结构 从入门到精通》
有需要的同学可以看看, 真心不错. 墙裂推荐… 最好能加上自己的思考和理解.


下面是我的公众号,干货文章不错过,有需要的可以关注下,有任何问题可以联系我:

本文相关源代码

更多推荐

数据结构与算法(九)Set集合和BinarySearchTree的时间复杂度分析

本文发布于:2024-02-11 20:51:27,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1683403.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:复杂度   数据结构   算法   时间   Set

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!