Chapter 2 Linked List
链表基础
链表是一种通过指针串联将需要存储的值在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。
- 涉及到的特殊概念
- 头节点
- 头节点是指链表中第一个节点,它是链表的入口点。
- 头节点通常包含链表的元数据信息,例如链表的长度、节点的类型等。
- 头节点可以是一个空节点,也可以包含一些数据。
- 尾节点
- 尾节点是指链表中最后一个节点,它是链表的结束点。
- 尾节点通常不包含任何数据,它的指针域指向null。
- 虚拟头节点
- 虚拟头节点是指链表中一个特殊的节点,它没有实际的数据,只是为了方便链表的操作而存在。
- 虚拟头节点通常在链表的头部添加,它的指针域指向链表的第一个节点。
- 虚拟头节点可以简化链表的操作,例如在链表的头部插入节点、删除节点等。
- 虚拟尾节点
- 虚拟尾节点是指链表中一个特殊的节点,它没有实际的数据,只是为了方便链表的操作而存在。
- 虚拟尾节点通常在链表的尾部添加,它的指针域指向null。
- 虚拟尾节点可以简化链表的操作,例如在链表的尾部插入节点、删除节点等。
- 空链表
- 空链表是指链表中没有任何节点。
- 空链表通常不包含任何数据,它的指针域指向null。
- 空链表通常不包含任何数据,它的指针域指向null。
- 头节点
链表的类型
接下来说一下链表的几种类型:
单链表
单链表中的指针域只能指向节点的下一个节点。
双链表
每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。因此,双链表可以向前查询和向后查询。
环形链表
将单链表或者双链表的尾节点指向头节点,从而组成一个环形链表。
链表的存储方式
数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
链表的定义
// 单链表
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;
所以如果不定义构造函数使用默认构造函数的话,在初始化的时候就不能直接给变量赋值!
链表的操作
删除节点
实现思路
- 找到待删除节点的上一个节点。
- 让上一个节点的next指针指向待删除节点的下一个节点。
代码实现
func (l *ListNode) DeleteNode(val int) {
cur := l
for cur != nil && cur.Next != nil {
if cur.Next.Val == val {
cur.Next = cur.Next.Next
}
cur = cur.Next
}
}
添加节点
实现思路
- 找到待添加节点的上一个节点。
- 让待添加节点的next指针指向待添加节点的上一个节点的next指针指向的节点。
- 让待添加节点的上一个节点的next指针指向待添加节点。
代码实现
func (l *ListNode) AddNode(val int) {
cur := l
for cur!= nil && cur.Next!= nil {
cur = cur.Next
}
cur.Next = &ListNode{Val: val}
}