目录
链表的分类
前一篇讲的单链表:
struct SListNode
{
int data; //节点数据
struct SListNode* next; //指针变量用于保存下一个节点的数据
};
SList 即 single linked list,单链表全称是不带头单向不循环链表。
而链表的结构多样,以下一共有8种(2*2*2)链表结构。
链表说明:
1. 链表的单向或双向
单线链表可以通过前驱节点找到后继节点,但是无法通过后继节点找到前驱节点;
双向链表不但可以通过前驱节点找到后继节点,还可以通过后继节点找到前驱节点。
2. 链表的带头或不带头
注意:在上一篇单链表中的提到的“头节点”的“头”和“带头链表”的“头”不是一个概念。
单链表中的“头节点”指的是 第一个有效的节点;
“带头链表”的“头”指的是 无效的节点,称为哨兵位,它不保存任何有效的数据。
3. 链表的循环和不循环
循环链表的最后一个节点的next指向的是第一个节点,成为一个环。
人们常用的两种链表分别为:
单链表(不带头单向不循环链表)和双向链表(带头双向循环链表)。
单链表例题
1. 单链表相关算法OJ题1:移除链表元素
解题思路:
思路一:先遍历链表,遇到 val 就删除。
但是,执行删除操作修改指针的指向比较麻烦,所以再想想其他方法。
思路二:定义一个新链表,遍历原链表,找不为 val 的节点,在新链表执行尾插操作。
在逐个尾插时,有两种情况:
链表为空:插入的节点就是链表的头节点和尾节点;
链表不为空:插入的节点就是链表的新的尾节点;
示例代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
ListNode* NewHead, *NewTail;
NewHead = NewTail = NULL;
ListNode* pcur = head;
while(pcur)
{
//不是val,尾插新链表
if(pcur->val != val)
{
//链表为空
if(NewTail == NULL)
{
NewHead = NewTail = pcur;
}
//链表不为空
else
{
NewTail->next = pcur;
NewTail = NewTail->next;
}
}
//刚好是val,不插入,pcur向后找
pcur = pcur->next;
}
if(NewTail)
{
NewTail->next = NULL;
}
return NewHead;
}
2. 单链表相关算法OJ题2:链表的中间结点
解题思路:
思路一:遍历链表,统计链表节点的个数,通过除以2找到中间节点。
这个思路需要两层for循环:for(统计链表个数) 和 for(根据除以2找到中间节点)
思路二:使用快慢指针。让 show 指针每次走一步,让 fast 指针每次走两步。
当 fast 的 next 为空时(或者 fast 为空),show 指针刚好指向的就是中间节点。
示例代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
ListNode *show, *fast;
show = fast = head;
while(fast && fast->next)
{
//快慢指针
show = show->next;
fast = fast->next->next;
}
return show;
}
3. 单链表相关算法OJ题3:反转链表
解题思路:
思路一:创建新链表,遍历原链表的节点,将其插入新链表中。
思路二:创建三个指针,分别记录前驱节点、当前节点、后继节点。改变原链表指针指向。
让n2的next反向指向n1,n1走到n2,n2走到n3,n3 = n3->next……
示例代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {
//空链表
if(head == NULL)
{
return head;
}
//创建3个指针
ListNode* n1, *n2, *n3;
n1 = NULL;
n2 = head;
n3 = head->next;
//遍历原链表,修改指针指向
ListNode* pcur = head;
while(n2)
{
//修改n2指向
n2->next = n1;
//修改指针位置
n1 = n2;
n2 = n3;
if(n3)
{
n3 = n3->next;
}
}
return n1;
}
4. 单链表相关算法OJ题4:合并两个有序链表
解题思路:
创建新链表,两个原链表分别创建一个指针用于比较大小,小的一方插入新链表。
示例代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//链表为空
if(list1 == NULL)
{
return list2;
}
if(list2 ==NULL)
{
return list1;
}
ListNode* l1, *l2;
l1 = list1;
l2 = list2;
ListNode* NewHead,*NewTail;
NewHead = NewTail = NULL;
while(l1 && l2)
{
if(l1->val < l2->val)
{
//把l1插入新链表
if(NewHead ==NULL)
{
NewHead = NewTail = l1;
}
else
{
NewTail->next = l1;
NewTail = NewTail->next;
}
l1 = l1->next;
}
else
{
//把l2插入新链表
if(NewHead == NULL)
{
NewHead = NewTail = l2;
}
else
{
NewTail->next = l2;
NewTail = NewTail->next;
}
l2 = l2->next;
}
}
//l2到头l1还没
if(l1)
{
NewTail->next = l1;
}
//l1到头l2还没
if(l2)
{
NewTail->next = l2;
}
return NewHead;
}
优化重复代码后(增加了哨兵位):
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
if(list1 == NULL)
{
return list2;
}
if(list2 == NULL)
{
return list1;
}
ListNode *l1, *l2;
l1 = list1;
l2 = list2;
ListNode *NewHead, *NewTail;
NewHead = NewTail = (ListNode*)malloc(sizeof(ListNode));
while (l1 && l2) {
if (l1->val < l2->val)
{
NewTail->next = l1;
NewTail = NewTail->next;
l1 = l1->next;
}
else
{
NewTail->next = l2;
NewTail = NewTail->next;
l2 = l2->next;
}
}
// l2到头l1还没
if (l1) {
NewTail->next = l1;
}
// l1到头l2还没
if (l2) {
NewTail->next = l2;
}
ListNode* ret = NewHead->next;
free(NewHead);
return ret;
}
5. 单链表相关算法OJ题5:分割链表
解题思路:
定义两个新链表,一个存放大于等于 x 的节点,一个存放小于 x 的节点。遍历原链表节点将其放入新链表里,最后将两个链表相连。
示例代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x)
{
if(head == NULL)
{
return head;
}
//创建带头的大小链表
ListNode* lessHead, *lessTail;
ListNode* greaterHead, *greaterTail;
lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));
greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));
//遍历原链表,处理节点
ListNode* pcur = head;
while(pcur)
{
if(pcur->val < x)
{
//放到小链表中
lessTail->next = pcur;
lessTail = lessTail->next;
}
else
{
//放到大链表中
greaterTail->next = pcur;
greaterTail = greaterTail->next;
}
pcur = pcur->next;
}
greaterTail->next = NULL;
//链表连接
lessTail->next = greaterHead->next;
ListNode* ret = lessHead->next;
free(greaterHead);
free(lessHead);
return ret;
}