定义一个结构体,表示链表上每个节点的类型
typedef char LinkType;
typedef struct LinkNode {
LinkType data;
struct LinkNode* next;
} LinkNode;
1)逆序打印单链表.
void LinkListReversePrint(LinkNode* head)
{
if(head == NULL)
{
return;
}
LinkListReversePrint(head->next);
printf("[%c : %p] ",head->data,head);
}
这里使用递归的方法,递归出口 -> head == NULL
2 )不允许遍历链表, 在 pos之前插入
void LinkListInsertBefore(LinkNode** head, LinkNode* pos, LinkType value)
{
if(head == NULL)
{
return;
}
if((*head) == NULL)
{//当前链表为空,直接return
return;
}
LinkNode* new_node = CreateLinkNode(value);
if(pos == (*head))
{//如果head就是要找的位置,直接进行头插
new_node->next = (*head);
(*head) = new_node;
return;
}
//以下使用移花接木的方法,将新插入的value赋值给pos的data,再在pos之后插入新的元素
new_node->data = pos->data;
pos->data = value;
new_node->next = pos->next;
pos->next = new_node;
}
3)约瑟夫环
LinkNode* JosephCycle(LinkNode* head, size_t food) {
if(head == NULL)
{
return NULL;
}
LinkNode* cur = head;
while(cur != cur->next)
{
size_t i = 1;
for(;i < food; ++i)
{
cur = cur->next;
}
printf("删除的元素是 : %c\n",cur->data);
LinkNode* to_delete = cur->next;
cur->data = cur->next->data;
cur->next = to_delete->next;
DestoryLinkNode(to_delete);
}
printf("幸存者 : %c\n",cur->data);
return cur;
}
每次找到要删除的元素是,同样使用第二题移花接木的方法删除,这样就不用再找当前元素的头结点
4)单链表逆置
void LinkListReverse(LinkNode** head)
{
if(head == NULL)
{
return;
}
if((*head) == NULL)
{
return;
}
if((*head)->next == NULL)
{
return;
}
LinkNode* pre = (*head);
LinkNode* cur = pre->next;
LinkNode* tail = cur->next;
while(tail != NULL)
{
cur->next = *head;
pre->next = tail;
(*head) = cur;
cur = tail;
tail = cur->next;
}
cur->next = (*head);
(*head) = cur;
pre->next = NULL;
return;
}
5 )单链表的冒泡排序
void LinkListBubbleSort(LinkNode* head)
{
if (head == NULL)
{
return;
}
if (head->next == NULL)
{//只有一个节点
return;
}
LinkNode *cur = head;
while (cur->next != NULL)
{
cur = cur->next;
}//cur指向最后一个元素
LinkNode* out = head;
LinkNode* in = head;
for (; out ->next!= NULL; out = out->next)
{
for (in = head; in != cur; in = in->next)
{
if (in->data > in->next->data)
Swap(&(in->data), &(in->next->data));
}
cur = in;
}
}
6)将两个有序链表, 合并成一个有序链表
LinkNode* LinkListMerge(LinkNode* head1, LinkNode* head2)
{
if (head1 == NULL && head2 == NULL)
{//两个空链表
return NULL;
}
else if (head1 == NULL && head2 != NULL)
{
return head2;
}
else if (head1 != NULL && head2 == NULL)
{
return head1;
}
LinkNode *cur1 = head1;
LinkNode *cur2 = head2;
LinkNode *new_head = NULL;
LinkNode *tail = NULL;
//确定新的链表的头结点,应指向两个链表中的较小的
if (cur1->data > cur2->data)
{
new_head = tail = cur2;
cur2 = cur2->next;
if (cur2 == NULL)
{
tail->next = cur1;
return new_head;
}
}
else
{
new_head = tail = cur1;
cur1 = cur1->next;
if (cur1 == NULL)
{
tail->next = cur2;
return new_head;
}
}
while (cur1 != NULL && cur2 != NULL)
{
if (cur1->data > cur2->data)
{//cur1的值较小,先将cur1装入新链表
tail->next = cur2;
tail = cur2;
cur2 = cur2->next;
}
else
{
tail->next = cur1;
tail = cur1;
cur1 = cur1->next;
}
}
if (cur1 == NULL && cur2 != NULL)//cur2还没有走完
{
tail->next = cur2;
}
else if (cur1 != NULL && cur2 == NULL)//cur1还没走完
{
tail->next = cur1;
}
return new_head;
}
7)找到链表中间的节点
LinkNode* FindMidNode(LinkNode* head)
{
if(head == NULL)
{
return NULL;
}
if(head->next == NULL)
{
return NULL;
}
LinkNode* quick = head;
LinkNode* slow = head;
while(quick->next != NULL)
{
quick = quick->next;
if(quick ->next == NULL)
{
break;
}
quick = quick->next;
slow = slow->next;
}
return slow;
}
这里使用快慢指针的方法,快指针每次走两步,慢指针每次走一步,当快指针走到链表的末尾时,慢指针刚好走到链表的一半
8)找到倒数第 K 个节点.
LinkNode* FindLastKNode(LinkNode* head, size_t K)
{
if (head == NULL)
{//空链表
return NULL;
}
if (K > LinkListSize(head))
{//非法输入
return NULL;
}
LinkNode* quick = head;
LinkNode* slow = head;
while (K--)
{
quick = quick->next;
}
while (quick != NULL)
{
quick = quick->next;
slow = slow->next;
}
return slow;
}
这里也定义两个指针,快指针先走K步,之后两个指针都从当前位置向后走,当快指针走到了链表末尾,满指针的位置就是倒数第K个节点
9)删除倒数第K个节点
void EraseLastKNode(LinkNode** head, size_t K)
{
if(head == NULL)
{
return;
}
if((*head) == NULL)
{
return;
}
LinkNode* cur = FindLastKNode((*head),K);
if(cur == (*head))
{
(*head) = cur->next;
DestoryLinkNode(cur);
return;
}
if(cur->next == NULL)
{
LinkNode* pre = (*head);
while(pre->next != cur)
{
pre = pre->next;
}
pre->next = NULL;
DestoryLinkNode(cur); //这里的Destory是释放掉malloc申请的内存,防止内存泄漏
return;
}
LinkNode* to_delete = cur->next;
cur->data = to_delete->data;
cur->next = to_delete->next;
DestoryLinkNode(to_delete);
return;
}
这里同理,删除某一节点用的是移花接木的方法,不需要再去找当前节点的上一个节点
10)判定单链表是否带环. 如果带环返回当前的交点
LinkNode* HasCycle(LinkNode* head)
{
if(head == NULL)
{
return NULL;
}
LinkNode* quick = head;
LinkNode* slow = head;
while(quick->next != NULL && quick->next->next != NULL)
{
quick = quick->next->next;
slow = slow->next;
if(quick == slow)
{
return quick;
}
}
return NULL;
}
这里用的方法类似于快慢指针,快指针每次走两步,慢指针每次走一步,如果有环,快慢指针会相遇
注意 : 快指针走3步,满指针走1步这样的方法在有些情况下是不可以的
11) 如果链表带环, 求出环的长度
size_t GetCycleLen(LinkNode* head)
{
LinkNode* cur = HasCycle(head);
if (cur == NULL)
{//没有环
return 0;
}
size_t length = 1;
LinkNode* cur1 = cur->next;
while (cur1 != cur)
{
cur1 = cur1->next;
++length;
}
return length;
}
利用(10)的方法求出交点,在求换的长度
12)如果链表带环, 求出环的入口
LinkNode* GetCycleEntry(LinkNode* head)
{
LinkNode* cur = HasCycle(head);
if (cur == NULL)
{//没有环
return NULL;
}
int len = GetCycleLen(head);
LinkNode* cur1 = head;
LinkNode* cur2 = head;
while(len--)
{
cur1 = cur1->next;
}
while(cur1 != cur2)
{
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur1;
}
13)判定两个链表是否相交, 并求出交点
LinkNode* HasCross(LinkNode* head1, LinkNode* head2)
{
if (head1 == NULL || head2 == NULL)
{//空链表
return NULL;
}
size_t len1 = LinkListSize(head1);
size_t len2 = LinkListSize(head2);
LinkNode* cur1 = head1;
LinkNode* cur2 = head2;
if (len1 > len2)
{//如果head1比head2长 K ,就让head1先走 K 步.
size_t K = len1 - len2;
while (K--)
{
cur1 = cur1->next;
}
}
else if (len2 > len1)
{//如果head2比head1长 K ,就让head2先走 K 步.
size_t K = len2 - len1;
while (K--)
{
cur2 = cur2->next;
}
}
//当两个链表剩余长度相同时,继续往下走,如果有 cur1==cur2 的情况,证明有交点.
//如果是因为某一个链表为空跳出循环,证明没有交点.
while (cur1 != NULL && cur2 != NULL && cur1 != cur2)
{
cur1 = cur1->next;
cur2 = cur2->next;
}
if (cur1 == cur2 && cur1 != NULL)
{
return cur1;
}
return NULL;
}