逆序打印单链表
void LinkListReversePrint(LinkNode* head);
思路:使用递归, 通过栈的后进先出特性, 实现单链表的逆序输出
不允许遍历链表, 在 pos 之前插入
void LinkListInsertBefore(LinkNode** head, LinkNode* pos,
LinkType value);
思路:先插到pos之后,再和pos交换值
单链表逆置
void LinkListReverse(LinkNode** head);
思路:每次删除第一个结点的下一个结点,然后头插
单链表的冒泡排序
void LinkListBubbleSort(LinkNode* head);
思路:和传统冒泡排序一样,可以只比较两个结点值的大小,然后交换值
将两个有序链表, 合并成一个有序链表
LinkNode* LinkListMerge(LinkNode* head1, LinkNode* head2);
思路:两个链表从第一个开始比较,小的那个插入到一个新的头结点后面,如此循环,直到某一链表为空,将另一个链表剩余的部分插入到新链表后面
找到倒数第 K 个节点.
LinkNode* FindLastKNode(LinkNode* head, size_t K);
思路:两个指针,slow和fast, fast先走k步, 然后slow和fast一起走,当fast走完时,slow的位置就是第k个结点
删除倒数第K个节点
void EraseLastKNode(LinkNode** head, size_t K);
思路:先找到再删除
判定单链表是否带环. 如果带环返回1
LinkNode* HasCycle(LinkNode* head);
思路:设置指针slow和fast,slow一次走一步,fast一次走两步,如果它们从头出发,再次相遇了,则说明链表带环.
如果链表带环, 求出环的长度
size_t GetCycleLen(LinkNode* head);
思路:从它们相遇的地方标记一个指针,然后一次走一步,计数器加1,再次相遇,得出环长
如果链表带环, 求出环的入口
LinkNode* GetCycleEntry(LinkNode* head);
思路:环内快慢指针相遇的位置到入口的距离再加上N倍的环长 = 头结点到环入口的距离
![]()
即上图 XY= ZY+ N*环长 N>=0
判定两个链表是否相交. 链表可能带环
int HasCrossWithCycle(LinkNode* head1, LinkNode* head2);
有三种情况
1, 链表1带环, 链表2 不带环, 则两个链表肯定不相交, 因为一旦相交, 两个链表必定都带环.
2, 两个都带环, 交点在环外
如果两个都带环,那么求它们的环入口点,若两入口点相同,则两个链表环外相交
3, 两个都带环, 交点在环上
求环入口点,然后从入口点走,能遇到另一个入口点,则环上相交
求两个有序链表的交集
LinkNode* UnionSet(LinkNode* head1, LinkNode* head2);
定义两个指针 cur1 和 cur2 分别指向两个链表, 再创建一个新链表, 然后从第一个开始比较, 若他们的值相等, 创建一个新结点, 令他的值等于 cur1 的值, 然后插入新链表.
拷贝复杂链表
ComplexNode* CopyComplex(ComplexNode* head);
复杂链表就是多了一个 random 指针, 指向任意结点, 或者为空
思路: 把每个结点的后面都插入一个自身节点, 创建新结点, 拷贝它前一个结点的值, 并插入其后, 这样每个拷贝结点的 random 指向的肯定是 它前面那个结点 random 指向结点的下一个结点.
C语言代码实现
#include<stdio.h>
#include<stdlib.h>
#define DataType int
#define TESTHEAD printf("=====%s=====\n", __FUNCTION__);
typedef struct Node
{
DataType data;
struct Node* next;
struct Node* random;
}linklist, *plinklist;
//创建新结点
plinklist CreateNode()
{
plinklist Node = (plinklist)malloc(sizeof(linklist));
Node->random = NULL;
return Node;
}
//销毁结点
void DestoryNode(plinklist Node)
{
free(Node);
Node = NULL;
}
//链表初始化
void LinkListInit(plinklist* head)
{
*head = CreateNode();
(*head)->next = NULL;
(*head)->random = NULL;
printf("初始化完成\n");
}
//链表的插入(尾插)
void LinkListPushBack(plinklist* head, DataType data)
{
plinklist Node;
plinklist temp;
if((*head)->next == NULL)
{
Node = CreateNode();
Node->data = data;
(*head)->next = Node;
Node->next = NULL;
}
else if((*head)->next)
{
temp = *head;
while(temp->next)
{
temp = temp->next;
}
Node = CreateNode();
Node->data = data;
temp->next = Node;
Node->next = NULL;
temp = Node;
}
}
//顺序打印链表
void LinkListPrint(plinklist* head)
{
if((*head)->next == NULL)
{
printf("空链表\n");
return ;
}
plinklist temp = (*head)->next;
while(temp)
{
if(temp->random == NULL)
{
printf("[%d|%9p|NULL]\n", temp->data, temp->next);
}
else
{
printf("[%d|%9p][%d]\n", temp->data, temp->next, temp->random->data);
}
temp = temp->next;
}
}
//逆序打印单链表
void LinkListReversePrint(plinklist* head)
{
if(*head == NULL)
return ;
if((*head)->next)
{
LinkListReversePrint(&((*head)->next));
}
printf("[%d|%9p]\n", (*head)->data, (*head)->next);
}
//不允许遍历链表, 在 pos 之前插入
//思路:先在pos后插入,然后和pos的值交换
void LinkListInsertBeforePos(plinklist* head, plinklist pos, DataType data)
{
if(head == NULL)
{
printf("非法输入\n");
return ;
}
if((*head) == NULL)
{
printf("空链表\n");
return ;
}
plinklist temp = *head;
plinklist Node = CreateNode();
Node->data = data;
Node->next = pos->next;
pos->next = Node;
int tmp = Node->data;
Node->data = pos->data;
pos->data = tmp;
}
//单链表逆置
void LinkListReverse(plinklist* head)
{
if(head == NULL)
{
printf("非法输入\n");
return ;
}
if((*head)->next == NULL)
{
printf("空链表\n");