leetcode-master/problems/链表理论基础.md

146 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p align='center'>
<img src="https://img-blog.csdnimg.cn/20201215214102642.png" width=400 >
</p>
<p align="center">
<a href="https://github.com/youngyangyang04/leetcode-master"><img src="https://img.shields.io/badge/Github-leetcode--master-lightgrey" alt=""></a>
<a href="https://img-blog.csdnimg.cn/20201115103410182.png"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
<a href="https://img-blog.csdnimg.cn/20201210231711160.png"><img src="https://img.shields.io/badge/公众号-代码随想录-brightgreen" alt=""></a>
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
<a href="https://www.zhihu.com/people/sun-xiu-yang-64"><img src="https://img.shields.io/badge/知乎-代码随想录-blue" alt=""></a>
<a href="https://www.toutiao.com/c/user/60356270818/#mid=1633692776932365"><img src="https://img.shields.io/badge/头条-代码随想录-red" alt=""></a>
</p>
# 关于链表,你该了解这些!
什么是链表链表是一种通过指针串联在一起的线性结构每一个节点是又两部分组成一个是数据域一个是指针域存放指向下一个节点的指针最后一个节点的指针域指向null空指针的意思
链接的入口点称为列表的头结点也就是head。
如图所示:
![链表1](https://img-blog.csdnimg.cn/20200806194529815.png)
# 链表的类型
接下来说一下链表的几种类型:
## 单链表
刚刚说的就是单链表。
## 双链表
单链表中的节点只能指向节点的下一个节点。
双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。
双链表 既可以向前查询也可以向后查询。
如图所示:
![链表2](https://img-blog.csdnimg.cn/20200806194559317.png)
## 循环链表
循环链表,顾名思义,就是链表首尾相连。
循环链表可以用来解决约瑟夫环问题。
![链表4](https://img-blog.csdnimg.cn/20200806194629603.png)
# 链表的存储方式
了解完链表的类型,再来说一说链表在内存中的存储方式。
数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
链表是通过指针域的指针链接在内存中各个节点。
所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
如图所示:
![链表3](https://img-blog.csdnimg.cn/20200806194613920.png)
这个链表起始节点为2 终止节点为7 各个节点分布在内存个不同地址空间上,通过指针串联在一起。
# 链表的定义
接下来说一说链表的定义。
链表节点的定义,很多同学在面试的时候都写不好。
这是因为平时在刷leetcode的时候链表的节点都默认定义好了直接用就行了所以同学们都没有注意到链表的节点是如何定义的。
而在面试的时候,一旦要自己手写链表,就写的错漏百出。
这里我给出C/C++的定义链表节点方式,如下所示:
```
// 单链表
struct ListNode {
int val; // 节点上存储的元素
ListNode *next; // 指向下一个节点的指针
ListNode(int x) : val(x), next(NULL) {} // 节点的构造函数
};
```
有同学说了我不定义构造函数行不行答案是可以的C++默认生成一个构造函数。
但是这个构造函数不会初始化任何成员变化,下面我来举两个例子:
通过自己定义构造函数初始化节点:
```
ListNode* head = new ListNode(5);
```
使用默认构造函数初始化节点:
```
ListNode* head = new ListNode();
head->val = 5;
```
所以如果不定义构造函数使用默认构造函数的话,在初始化的时候就不能直接给变量赋值!
# 链表的操作
## 删除节点
删除D节点如图所示
![链表-删除节点](https://img-blog.csdnimg.cn/20200806195114541.png)
只要将C节点的next指针 指向E节点就可以了。
那有同学说了D节点不是依然存留在内存里么只不过是没有在这个链表里而已。
是这样的所以在C++里最好是再手动释放这个D节点释放这块内存。
其他语言例如Java、Python就有自己的内存回收机制就不用自己手动释放了。
## 添加节点
如图所示:
![链表-添加节点](https://img-blog.csdnimg.cn/20200806195134331.png)
可以看出链表的增添和删除都是O(1)操作,也不会影响到其他节点。
但是要注意要是删除第五个节点需要从头节点查找到第四个节点通过next指针进行删除操作查找的时间复杂度是O(n)。
# 性能分析
再把链表的特性和数组的特性进行一个对比,如图所示:
![链表-链表与数据性能对比](https://img-blog.csdnimg.cn/20200806195200276.png)
数组在定义的时候,长度就是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。
链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景。
相信大家已经对链表足够的了解,后面我会讲解关于链表的高频面试题目,我们下期见!