数据结构整理

常用数据结构时间复杂度

数据结构 新增 查询/Find 删除/Delete GetByIndex
数组 Array (T[]) O(n) O(n) O(n) O(1)
链表 Linked list (LinkedList<T>) O(1) O(n) O(n) O(n)
Resizable array list (List<T>) O(1) O(n) O(n) O(1)
Stack (Stack<T>) O(1) - O(1) -
Queue (Queue<T>) O(1) - O(1) -
Hash table (Dictionary<K,T>) O(1) O(1) O(1) -
Tree-based dictionary(SortedDictionary<K,T>) O(log n) O(log n) O(log n) -
Hash table based set (HashSet<T>) O(1) O(1) O(1) -
Tree based set (SortedSet<T>) O(log n) O(log n) O(log n) -

Map

map用来存储k、v结构数据,相信大家使用的都比较熟练了,现在我们就深入分析一下它的细节。

Java中的Map

map都有哪些方法?


image.png

这个是map的接口规定了一系列的操作方法以及一个Entity接口。


image.png

这个是Java集合的类图,可以看到Map的一些主要实现。

HashMap的原理

在HashMap中存储的元素定义如下

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;  // key的hash值
    final K key;     //  key值
    V value;         //  value值
    Node<K,V> next;  // 下一个node
    ... ...
}

HashMap中定义了一个Node数组,用来存放Node,这些Node根据key的hash值均匀分布在数组上,但是不可避免的存在hash冲突(不同Node它们的key的hash值相同),那么就在每个数组元素上向后拓展链表结构。
查询的时候,先根据key的hash确定数组下标,然后再使用equals方法遍历链表比较值最终找到想要的Node并返回。
这里有一些关键数据,Node数组的初始大小为16(2的n次方),hash冲突链表长度超过8将转换为红黑树(红黑树查询速度比链表快),map会记录一共存了多少个Node就是size,同时规定了一个加载因子loadFactor默认为0.75,利用这个加载因子来估算当前map最大能存多少个Node比较合理就是threshold(最大容量)。
插入的时候一旦size>threshold了就需要扩容,扩容时Node数组大小*2,并将所有的Node重新hash存一遍,这部分开销较大。每次结构发生改变会记录到变量modCount(结构变化次数)中。

TreeMap

参考: TreeMap原理实现及常用方法

基础概念

结点:树中的每个元素称为结点
根结点:最顶上的结点,一个树只有一个根结点
每个结点可以拥有子树,一个结点的所有子树都不想交
普通树

image.png

结点的度:一个结点有几个子节点就有几度
结点关系:父结点、子结点、兄弟结点
结点层次:最大层数表示树的深度
image.png

二叉树:结点的度不超过2,结点在左在右是有顺序的
左斜树:左左左左左
右斜树:右右右右右
满二叉树:最后一层结点的度为0,其他层结点的度都为2
image.png

完全二叉树:把满二叉树按层、从左到右编号。按编号新填充一个二叉树,这个树就是个完全二叉树
按顺序填充ABCDEF就是个完全二叉树
image.png

二叉树

二叉树存储结构:如果每一层用一个数组存,显然有的地方没有结点,会浪费数组资源。
所以使用二叉链表

image.png

代码表示:

typedef struct BiTNode{
    TElemType data;//数据
    struct BiTNode *lchild, *rchild;//左右孩子指针
} BiTNode, *BiTree;

image.png

二叉树遍历
image.png

前序遍历根左右
ABDECF
中序遍历左根右
DBEAFC
后序遍历左右根
DEBFCA
层序遍历:逐层从左到右
[A]
[BC]
[DEF]

二叉搜索树BST

二叉搜索树(二叉查找树)BST:左结点<根结点<右结点

image.png

每个结点结构如下:
image.png

:1.查找到空没结果;2.值相等查找成功;3.小于结点递归查找其左子树,大于结点递归查找其右子树;
:1.存在不插入;2.不存在,执行查找时执行到哪个位置就插入到哪个位置;
:1.若为叶子结点直接删;2.若只有左子树或右子树,将左子树或右子树代替该结点;3.若左右子树都存在,找到左子树中最大值结点,替换到待删除的位置

平衡二叉树AVL

平衡二叉树AVL
当结点数目一定时,保持树的左右两端平衡,树的查找效率最高。这种左右子树层级相差不超过1的树叫平衡二叉树。 AVL是通过平衡深度来解决BST的搜索效率降低的策略。

image.png

平衡因子:结点的左子树与右子树的高度(深度)差叫做平衡因子(0,-1,1)
平衡二叉树代码结构

typedef struct AVLNode *Tree;
typedef int ElementType;
struct AVLNode
{
    int depth; //深度,这里计算每个结点的深度,通过深度的比较可得出是否平衡
    Tree parent; //该结点的父节点,方便操作
    ElementType val; //结点值
    Tree lchild;
    Tree rchild;
    AVLNode(int val=0) //默认构造函数
    {
        parent=NULL;
        depth=0;
        lchild=rchild=NULL;
        this->val=val;
    }
};

左旋:右子树过深,要平衡到左边去

image.png

因为右子树深度超出左子树深度2,要进行左旋平衡,流程:
1.原根结点的右结点代替根节点
2.现根节点的左子树变为原根节点的右子树
3.原根节点变为现根节点的左子树
右旋:左子树过深,要平衡到右边去
方向相反,流程同上
image.png

插入结点
在根结点的左孩子的左子树插入结点LL:直接右旋
在根结点的右孩子的右子树插入结点RR:直接左旋
在根结点的左孩子的右子树插入结点LR:先对根结点的左孩子左旋,在对根结点右旋
在根结点的右孩子的左子树插入结点RL:先对根结点的右孩子右旋,在对根结点左旋
删除
删除流程同二叉搜索树,但要考虑删除后是否平衡,不平衡要进行调整。

2-3树

2-3树:AVL虽然解决了BST的查询效率降低问题,但是却引入了插入、删除时的繁琐操作,这些性能的损耗可能会大于检索带来的提升。所以引入了2-3树。存在2度、3度结点,2度结点结构同BST,3度结点数据域a、b,3个指针,左子树所有结点小于a,中子树所有结点在ab之间,右子树所有结点大于b。
2-3树的查找:同BST,都是通过比较选定路线继续查找。

image.png

2-3树插入

2-3-4树

2-3树不再是单纯的二叉树了,因为2-3树中除了2-节点之外还存在3-节点。在2-3树的基础上进一步扩展,2-3-4树在2-3树的基础上添加4-节点。4-节点可以存储3个键值,最多可以拥有4棵子树。


image.png

红黑树

2-3-4树和红黑树是完全等价的,但是2-3-4树的编程实现相对复杂,所以一般是通过实现红黑树来实现替代2-3-4树,而红黑树也同样保证在O(logN)的时间内完成查找、插入和删除操作。


image.png

B树

数据量大如数据库时,不能全放内存,需要放磁盘,每一个结点代表一个磁盘页,访问一次新结点代表一次磁盘io,那么树的高度决定磁盘io的次数,所以让每个结点增加key值,就可以将“瘦高”的树变为“矮胖”的树。


image.png

B+树

在B树的基础上优化,分为索引结点(只存key不存data)、叶子结点(key、data),叶子结点使用链表连接。


image.png

(1)B+树中索引节点只存储key值,不存储数据,则相同的大小磁盘页中,使用B+树可以存储更多的节点元素,使得B+树比B树更为矮胖,减少磁盘IO次数。

(2)在查找单一元素时,B树最好情况是在根节点查找成功,最坏情况是查找至叶子节点,导致B树的查找过程是不稳定的。而使用B+—树的查找最终查找节点为叶子节点,使得B+树查找稳定。

(3)在进行某个范围内数据查找,B树需要进行中序遍历,而B+树的叶子节点采用单链表形式链接,只需按顺序遍历链表即可完成范围查找,提高了查找效率。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352