基础数据结构(漫画算法第二章)

数据结构基础

关键词:数组 链表 队列 哈希表

数据结构的操作无非是增删改查4种情况

数组

数组读取元素和更新元素的时间复杂度都是O(1)

插入元素

插入数组元素的操作存在3种情况

尾部插入:直接把插入的元素放在数组尾部的空闲位置即可,等同于更新元素的操作

中间插入:首先把插入位置及后面的元素向后移动,再把要插入的元素放对应的数组位置上

function insert(ele,arr,size){
    let length = arr.length
	if(size < 0 || size > arr.length){
        throw new Error('超出范围限制!')
    }
    for(let i = length - 1; i >= size; i--){
        arr[i + 1] = arr[i]
    }
    arr[size] = ele
}

超范围插入:先扩容,具体操作是创建一个新数组,长度是旧数组的2倍,再把旧数组中的元素全部复制到新数组

删除元素

如果删除的元素位于数组中间,那么其后的元素都需要向前挪一位

for(let i = index ; i < length - 1; i++){
	arr[i] = arr[i + 1]
}

数组插入和删除操作的时间复杂度都是O(n)

链表

链表是一种物理上非连续,非顺序的数据结构,由若干节点(node)所组成

单向链表

单向链表的每一个节点又包含两部分,一部分是存放数据的变量data,另一部分是指向下一个节点的指针next

链表的第一个节点被称为头节点,最后一个节点被称为尾节点,尾节点的next指针指向空,与数组按照下标来随机寻找元素不同,对于链表的其中一个节点A,我们只能根据节点A的next指针来找到该节点的下一个节点B,再根据节点B的next指针找到下一个节点C…

双向链表

双向链表的每一个节点除了拥有data和next指针,还拥有指向前置节点的prev指针,如果说数组在内存中的存储方式是顺序存储,那么链表在内存中的存储方式则是随机存储

查找节点

链表只能从头节点开始向后一个一个节点逐一查找

第一步,将查找的指针定位到头节点

第二步,根据头节点的next指针,定位到第2个节点,依次查找

由于链表中的数据只能按顺序进行访问,最坏的时间复杂度是O(n)

插入节点

尾部插入:把最后一个节点的next指针指向新插入的节点即可

头部插入

第一步,把新节点的next指针指向原来的头节点

第二步,把新节点变为链表的头节点

中间插入

第一步,新节点的next指针,指向插入位置的节点

第二步,插入位置前置节点的next指针,指向新节点

删除元素

尾部删除:把倒数第2个节点的next指针指向空即可

头部删除:把链表的头节点设为原先头节点的next指针即可

中间删除:把要删除节点的前置节点的next指针指向要删除元素的下一个节点即可

如果不考虑插入,删除操作之前查找元素的过程,只考虑纯粹的插入和删除操作,时间复杂度都是O(1)

数组和链表都属于线性的数据结构,对于读操作多,写操作少的场景来说,用数组更合适一些,如果需要在尾部频繁插入,删除元素,用链表更合适一些

物理结构和逻辑结构

物理结构

常用的数据结构有很多,但是大部分都以数组或链表作为作为存储方式,数组和链表可以被看作数据存储的“物理结构”

逻辑结构

如果把物质层面的人体比作数据存储的物理结构,那么精神层面的人格则是数据存储的逻辑结构·。逻辑结构是抽象的概念,它依赖于物理结构而存在

栈是一种线性数据结构,栈中的元素只能先入后出,最早进入的元素存放的位置叫做栈底,最后进入的元素存放的位置叫做栈顶。栈即可以用数组实现,也可以用链表实现

入栈和出栈只会影响到最后一个元素,不涉及其他元素的整体移动,所以无论是以数组还是以链表实现,入栈出栈的时间复杂度都是O(1)

栈通常用于实现递归的逻辑

队列

队列中的元素只能先入先出,队列的出口端叫作队头,队列的入口端叫做队尾

用数组实现时,为了入队操作的方便,把队尾位置规定为最后入队元素的下一个位置

入队就是把新元素放入队列中,只允许在队尾的位置放入元素,出队就是把元素移出队列,只允许在队头一侧移出元素

循环队列

假设一个队列经过反复的入队和出队操作,还剩下两个元素,在"物理上"的末尾位置,这时又有一个新元素将要入队;在数组不扩容的前提下,可以利用已出队元素留下的空间,让队尾指针重新指回数组的首位,这样就实现了一个循环队列。在物理存储上,队尾的位置也可以在队头前。当再有元素入队时,将其放入数组的首位,队尾指针继续后移即可;一直到(队尾下标+1)%数组长度 = 队头下标时,代表此队列真的已经满了。需要注意的是,队尾指针指向的位置永远空出一位,所以队列最大容量比数组长度小1。循环队列入队出队的时间复杂度同样是O(1)

双端队列

即把栈和队列的特点的结合起来,既可以先入先出,也可以先入后出

优先队列

遵循谁的优先级最高,谁先出队

散列表

散列表也叫哈希表,这种数据结构提供了键(key)和值(value)的映射关系。只要给出一个key,就可以高效查找它所匹配的Value,时间复杂度为O(1),散列表的本质是数组

哈希函数

通过某种方式把key和数组下标进行转换,这种中转站叫做哈希函数

哈希冲突

不同的key通过哈希函数获得的下标有可能是相同的,哈希冲突的解决解决方法一种是开放寻址法,一种是链表法

散列表的扩容(扩展长度)

第一步:创建一个新的Entry空数组,长度是原数组的2倍

第二步:重新Hash,遍历原Entry数组,把所有的Entry重新Hash到新数组中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值