5.链表(上)

应用:LRU缓存淘汰算法

链表也是一种线性表

链表的内存结构是不连续的内存空间,将一组不连续的内存空间串联起来,从而进行数据存储的数据结构。

链表中每个内存块儿被称为节点Node, 节点除了存储数据外,还需要记录链表上指向下一个节点的地址,即后继指针next.

链表特点

1.插入、删除数据效率O(1)级别(只需要改指针).

随机访问效率O(n)级别。(需要从链表头到链尾进行遍历)

2.和数组比,内存空间消耗更大,因为每个存储数据的节点需要额外的空间存储后继指针。

常用的链表:单链表,循环链表,双链表

1.单链表:

(1)每个节点只包含一个指针,即后继指针。

(2)有两个特殊的节点,首节点和尾节点。用首节点的地址表示链表的地址,尾节点的后继指针为NULL.

(3)性能特点:插入、删除时间复杂度 O(1),查找时间复杂度O(n).

2.循环链表

(1)除了尾节点的后继指针指向首节点外,均与单链表一致。

(2)适用于存储有循环特点的数据,如约瑟夫问题。

3.双向链表

(1)节点除了存储数据外,还有两个指针分别指向前一个节点地址和后一个节点地址。

(2)首节点的前驱指针和尾节点的后继指针均指向NULL.

(3) 和单链表比,存储相同的数据,需要更多的存储空间。插入、删除操作比单链表效率高。

数组和链表对比

1.数组缺点

(1)若申请内存空间很大,比如100M,但内存空间没有100M的连续空间,则申请失败,即使内存可用空间大于100M.

(2)大小固定,若存储空间不足,则需要进行扩容,一旦扩容就需要数据复制,这是非常耗时的。

2.链表缺点

(1)内存空间消耗更大,因为需要额外的空间存储指针信息。

(2)对链表频繁的插入和删除操作,会导致频繁的内存申请和释放,容易造成内存碎片。

cpu缓存机制

数组简单易用,在实现上使用的是连续的内存空间,可以借助 CPU 的缓存机制,预读数组中的数据,所以访问效率更高。而链表在内存中并不是连续存储,所以对 CPU 缓存不友好,没办法有效预读。

CPU在从内存读取数据的时候,会先把读取到的数据加载到CPU的缓存中。而CPU每次从内存读取数据并不是只读取那个特定要访问的地址,而是读取一个数据块(这个大小我不太确定。。)并保存到CPU缓存中,然后下次访问内存数据的时候就会先从CPU缓存开始查找如果找到就不需要再从内存中取。这样就实现了比内存访问速度更快的机制,也就是CPU缓存存在的意义:为了弥补内存访问速度过慢与CPU执行速度快之间的差异而引入

对于数组来说,存储空间是连续的,所以在加载某个下标的时候可以把以后的几个下标元素也加载到CPU缓存这样执行速度会快于存储空间不连续的链表存储。

链表写作技巧

1.理解指针或引用的含义

将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指针,或者反过来说,指针中存储了这个变量的内存地址,指向了这个变量,通过指针就能找到这个变量。

p->next=q。这行代码是说,p 结点中的 next 指针存储了 q 结点的内存地址。

p->next=p->next->next。这行代码表示,p结点的 next 指针存储了 p 结点的下下一个结点的内存地址。

变量是存储值的,每一个变量都有地址。

指针的值是一个变量的地址。

使用指针,可以在无需知道变量名的情况下,间接读取或更新变量的值。

go语言的方式:

声明变量 var x int 表达式&x(x的地址)获取一个指向整型变量的指针,它的类型是整型指针(*int)。

如果指针的值叫做p,我们说p指向x, 或p包含x的地址。

p指向的变量写成*p, 表达式*p表示获取变量的值,一个整型。

*p代表一个变量,可以出现在赋值操作符左边,用于更新变量的值。

x := 1

p := &x //p是一个指向变量x地址的指针

fmt.Println(*p) //*p,获取指针p指向的变量的值,即x的值

*p = 2 //即x = 2, 通过指针p改变变量x的值

fmt.Println(x) //输出2

结构体的成员或数组的元素都是变量。

指针类型的零值是nil,测试 p != nil,结果true,说明p指向一个变量。

两个指针当前仅当指向同一个变量或者两者都是nil,才相等。

2.警惕指针丢失和内存泄露

如在链表中插入新节点的操作顺序

x->next = p->next

p->next = x

3.利用哨兵简化实现难度

4.重点留意边界条件处理

如果链表为空时,代码是否能正常工作?

如果链表只包含一个结点时,代码是否能正常工作?

如果链表只包含两个结点时,代码是否能正常工作?

代码逻辑在处理头结点和尾结点的时候,是否能正常工作?

5.学会画图

画流程图,把逻辑画在图上

6.多写多练

单链表反转

链表中环的检测

两个有序的链表合并

删除链表倒数第 n 个结点

求链表的中间结点

发布了127 篇原创文章 · 获赞 24 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/Linzhongyilisha/article/details/99348299