在各大考试中,链表是一个十分重要的考点,本篇博客将着重介绍几道常见的关于链表的例题。
- 从尾到头打印链表
- 删除一个无头单链表的非尾节点(不能遍历链表)
- 在一个无头单链表的一个节点前插入一个节点(不能遍历链表)
- 单链表实现约瑟夫环
- 逆置/反转单链表
- 单链表冒泡排序
- 合并两个有序链表
- 找到链表的中间节点
- 查找单链表倒数第k个节点(要求只能遍历一遍链表)
- 删除链表的倒数第k个节点
- 判断单链表是否带环,带环返回相遇点的指针
- 求环的入口点
- 若链表带环,求环的长度
- 判断两个链表是否相交,并求出交点
求两个已排序单链表中相同的数据
我们来一道一道的解决问题
1. 从尾到头打印链表
分析:利用递归的思想就可以实现从尾到头打印单链表
代码:
void LinkListPrintReverse(LinkNode* phead){
if(phead == NULL){
//空链表
return;
}
LinkListPrintReverse(phead->next);
printf("%c ",phead->data);
return;
}
2.删除一个无头单链表的非尾节点(不能遍历链表)
分析:将要删除节点的下一个节点的值赋给要删除的节点,再删除下一个节点,这样就避免了单链表不遍历链表就找不到前一个节点的尴尬(乾坤大挪移)。
代码:
void LinkListErase3(LinkNode** phead,LinkNode** pos){
if(phead == NULL){
//非法输入
return;
}
if(*phead == NULL){
//空链表
return;
}
if(*pos != NULL && (*pos)->next != NULL){
LinkNode* to_delete = (*pos)->next;
(*pos)->data = (*pos)->next->data;
(*pos)->next = (*pos)->next->next;
to_delete->next = NULL;
free(to_delete);
}
if((*pos)->next == NULL){
return;
}
return;
}
3.在一个无头单链表的一个节点前插入一个节点(不能遍历链表)
分析:我们可以创建一个和要插入的节点一样的节点,插入到指定节点的后面,然后将要需要插入的值赋给指定节点。(乾坤大挪移)
代码:
void LinkListInsertSp(LinkNode** phead, LinkNode* pos, LinkNodeType value){
if(phead == NULL || pos == NULL){
//非法输入
return;
}
if(*phead == NULL){
//空链表
return;
}
LinkNode* tmp = CreateNode(pos->data);
tmp->next = pos->next;
pos->next = tmp;
pos->data = value;
return;
}
4.单链表实现约瑟夫环
分析:每次数到指定数目,开始从下一个元素重新计数。
代码:
LinkNode* JoseCycle(LinkNode* phead,size_t food){
if(phead == NULL){
return NULL;
}
if(food == 0){
return NULL;
}
LinkNode* cur = phead;
//当最终只剩一个元素的时候,cur == cur->next,停止循环。
while(cur != cur->next){
size_t i = 0;
for(; i < (food - 1); ++i){
cur = cur->next;
}
LinkNode* to_delete = cur->next;
cur->data = cur->next->data;
cur->next = cur->next->next;
free(to_delete);
}
return cur;
}
5.逆置/反转单链表
分析:每次取下一个节点放到头结点的前面,然后将头指针前移。
代码:
void LinkListReverse(LinkNode** phead){
if(phead == NULL){
//非法输入
return;
}
if(*phead == NULL){
//空链表
return;
}
if((*phead)->next == NULL){
//只有一个节点
return;
}
LinkNode* cur = *phead;
while(cur->next != NULL){
LinkNode* to_delete = cur->next;
cur->next = to_delete->next;
to_delete->next = *phead;
*phead = to_delete;
}
return;
}
6.单链表冒泡排序
分析:没啥分析的,类似普通的冒泡排序
代码;
void Swap(LinkNodeType* a,LinkNodeType* b){
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
void LinkListBubble(LinkNode* phead){
if(phead == NULL){
return;
}
LinkNode* count = phead;
LinkNode* tail = NULL;
for(;count != NULL;count = count->next){
LinkNode* cur = phead;
for(; cur->next != tail; cur = cur->next){
if(cur->data > cur->next->data){
Swap(&(cur->data) , &(cur->next->data));
}
}
tail = cur;
}
}
7.合并两个有序链表
分析:设置两个指针cur1,cur2 分别遍历链表,如果cur1的值小于cur2的值,因为链表十有序的,所以将cur1指向的内容存到新链表后,cur1 后移,同理,如果cur2的值小于cur1 的值,将cur2的值存到新链表后cur2后移。如果两指针指向的值相等,那么将两指针同时后移。最后如果有一个链表遍历结束,那么将另外一个链表剩下的部分加到新链表之后。
代码:
LinkNode* LinkListMerge(LinkNode* phead1,LinkNode* phead2){
if(phead1 == NULL){
return phead2;
}
if(phead2 == NULL){
return phead1;
}
LinkNode* cur1 = phead1;
LinkNode* cur2 = phead2;
LinkNode* new_head = NULL;
//设置tail指针是为了每次都能找到最后一个节点
LinkNode* new_tail = NULL;
while(cur1 != NULL && cur2 != NULL){
if(cur1->data < cur2->data){
if(new_head == NULL){
//新链表里还没有元素
new_head = new_tail = cur1;
}
else{
new_tail->next = cur1;
new_tail = new_tail->next;
}
cur1 = cur1->next;
}
if(cur1->data >= cur2->data){
if(new_head == NULL){
new_head = new_tail = cur2;
}
else{
new_tail->next = cur2;
new_tail = new_tail->next;
}
cur2 = cur2->next;
}
}
if(cur1 != NULL){
//cur2遍历结束,而cur1还未遍历完,将cur1接入新链表。
new_tail->next = cur1;
}
if(cur2 != NULL){
new_tail->next = cur2;
}
return new_head;
}
8.找到链表的中间节点
分析:设置两个指针,分别是fast.slow。fast每次后移两个节点,slow每次后移一个节点,所以当fast遍历到最后一个节点,slow正好指向链表的中间节点。
代码:
LinkNode* LinkListFindMid(LinkNode* phead){
if(phead == NULL){
return NULL;
}
LinkNode* fast = phead;
LinkNode* slow = phead;
while(fast->next != NULL && fast->next->next != NULL){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
9.查找单链表倒数第k个节点(要求只能遍历一遍链表)
分析:设置两个指针,分别为fast,slow ,先让fast走步,这样slow到fast的距离就为k,然后,fast与slow同时后移。直到fast指向空,此时slow指向的位置就是倒数第k个位置。
代码:
LinkNode* LinkListFindKth(LinkNode* phead,size_t k){
LinkNode* fast = phead;
LinkNode* slow = phead;
size_t i = 0;
for(;i < k && fast != NULL;i++){
fast = fast->next;
}
if(i < k){
return NULL;
}
while(fast != NULL){
fast = fast->next;
slow = slow->next;
}
return slow;
}
10.删除链表的倒数第k个节点
分析:根据上道题,只要找到倒数第k个节点,我们就有一万种方法删除掉这节点。
代码:
void LinkListEraseKth(LinkNode** phead,size_t k){
if(phead == NULL){
return;
}
if(*phead == NULL){
return;
}
size_t size = LinkListSize(*phead);
//如果k大于size,超出了范围,无法删除
if(k > size){
printf("超出范围,无法删除!\n");
return;
}
LinkNode* pos_k = LinkListFindKth(*phead,k);
if(pos_k->next != NULL){
LinkNode* tmp = pos_k->next;
pos_k->data = pos_k->next->data;
pos_k->next = tmp->next;
DestroyNode(tmp);
}
else if(pos_k->next == NULL){
LinkListPopBack(phead);
}
return;
}
11.判断单链表是否带环,带环返回相遇点的指针
分析:设置两个指针,fast,slow,每次fast指针向后移两个指针,slow向后位移一个指针,如果一个链表带环,fast和slow一定还会再次相遇。因此,若果两个指针再次相遇,我们认为链表带环,如果链表不带环,fast一定会走到NULL。
代码:
LinkNode* LinkListHasCycle(LinkNode* phead){
if(phead == NULL){
//空链表
return NULL;
}
LinkNode* fast = phead;
LinkNode* slow = phead;
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
//快慢指针再次相遇,链表一定带环
return fast;
}
}
//函数走到这儿一定不带环
return NULL;
}
12.求环的入口点
分析:假设两个快慢指针,slow、fast,每次fast走两步,slow走一步,如果链表带环,那么快慢指针会再次相遇,此时,slow走过得路程是 x + z , fast走过得路程是 x + z + 环长,又因为fast 走的路程是slow走过得路程的2倍,所以可得 x = y。
分析到这儿,我们就可以设置一个指针cur从头结点开始每次走一步,另一个指针meet_pos从相遇出开始走,每次走一步,那么,cur和meet_pos相遇的位置就是链表环的入口点。
代码:
LinkNode* LinkListCycleEntryPos(LinkNode* phead){
if(phead == NULL){
//空链表
return NULL;
}
LinkNode* meet_pos = LinkListHasCycle(phead);
//meet_pos = NULL说明链表无环
if(meet_pos == NULL){
return NULL;
LinkNode* cur = phead;
while(cur != meet_pos){
cur = cur->next;
meet_pos = meet_pos->next;
}
return cur;
}
13.若链表带环,求环的长度
分析:设置一个指针从相遇点开始遍历,再次走到相遇点走过的长度就是环的长度。
size_t LinkListCycleSize(LinkNode* phead){
LinkNode* meet_pos = LinkListHasCycle(phead);
if(meet_pos == NULL){
return 0;
}
LinkNode* cur = meet_pos;
size_t count = 1;
for(;cur->next != meet_pos;cur = cur->next){
++count;
}
return count;
}
14.判断两个链表是否相交,并求出交点
分析:两个链表可能一个带环,一个不带环;两个都带环;两个都不带环。
一个带环,一个不带环:一定不相交
都不带环:求两个链表的长度,并求长度差offset,较长的链表先走长度差offset步,然后两个链表同时遍历,如果两个指针会相遇,那么相遇点就是两链表的交点。
都带环
交点在环外
交点求法类似都不带环的求法,求两个链表头结点到入口点的距离,并求距离差offset,较长的先走offset步,然后一起走,相遇点就是交点。
交点在环内
返两个链表的任意一个入口点作为交点返回。
代码:
LinkNode* LinkListHasCyclePos(LinkNode* phead1,LinkNode* phead2){
if(phead1 == NULL || phead2 == NULL){
return NULL;
}
//入口点
LinkNode* meet_pos1 = LinkListHasCycle(phead1);
LinkNode* meet_pos2 = LinkListHasCycle(phead2);
LinkNode* cur1 = phead1;
LinkNode* cur2 = phead2;
if(meet_pos1 == NULL && meet_pos2 == NULL ){
size_t size1 = LinkListSize(phead1);
size_t size2 = LinkListSize(phead2);
size_t offset = 0;//距离差
if(size1 > size2){
offset = size1 - size2;
size_t i = 0;
for(;i < offset;++i){
cur1 = cur1->next;
}
while(cur1 != NULL && cur2 != NULL){
if(cur1 == cur2){
return cur1;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
}else if(size1 <= size2){
offset = size2 - size1;
size_t i = 0;
for(;i < offset; ++i){
cur2 = cur2->next;
}
while(cur1 != NULL && cur2 != NULL){
cur1 = cur1->next;
cur2 = cur2->next;
if(cur1 == cur2){
return cur1;
}
}
}
return NULL;
}
else if(meet_pos1 != NULL && meet_pos2 != NULL){
LinkNode* Entry1 = LinkListCycleEntryPos(phead1);
LinkNode* Entry2 = LinkListCycleEntryPos(phead2);
size_t offset = 0;
if(Entry1 == Entry2){
size_t size1 = 0;
size_t size2 = 0;
for(;cur1 != Entry1;cur1 = cur1->next){
size1++;
}
for(;cur2 != Entry2;cur2 = cur2->next){
size2++;
}
cur1 = phead1;
cur2 = phead2;
if(size1 >= size2){
offset = size1 - size2;
size_t i = 0;
for(;i < offset;++i){
cur1 = cur1->next;
}
while(cur1 != Entry1 && cur2 != Entry2){
if(cur1->data == cur2->data){
return cur1;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
}else if(size1 < size2){
offset = size2 - size1;
size_t i = 0;
for(;i < offset;++i){
cur2 = cur2->next;
}
while(cur1 != Entry1 && cur2 != Entry2){
if(cur1->data == cur2->data){
return cur1;
}
cur1 = cur1->next;
cur2 = cur2->next;
}
}
}
if(Entry1 != Entry2){
return Entry1;
}
}
else{
return NULL;
}
return NULL;
}
求两个已排序单链表中相同的数据
分析:设置两个指针cur1、cur2分别遍历链表,如果 cur1->data > cur2->data
将 cur2->data存到新的链表,并且cur2后移到下个节点,同理,
cur2->data > cur1->data 将 cur1->data存到新的链表,并且cur1后移到下个节点。
若 cur1->data == cur2->data, 将cur1->data和cur2->data 都存到新链表中,两指针同时后移。
LinkNode* UnionSet(LinkNode* phead1,LinkNode* phead2){
if(phead1 == NULL || phead2 == NULL){
return NULL;
}
LinkNode* cur1 = phead1;
LinkNode* cur2 = phead2;
LinkNode* new_head = NULL;
LinkNode* new_tail = NULL;//定义一个尾指针,便于找到最后一个节点
while(cur1 != NULL && cur2 != NULL){
if(cur1->data > cur2->data){
cur2 = cur2->next;
}else if(cur1->data < cur2->data){
cur1 = cur1->next;
}else{
LinkNode* new_node = CreateNode(cur1->data);
if(new_node == NULL){
return NULL;
}
if(new_head == NULL){
new_head = new_tail = new_node;
cur1 = cur1->next;
cur2 = cur2->next;
}else{
new_tail->next = new_node;
new_tail = new_tail->next;
cur1 = cur1->next;
cur2 = cur2->next;
}
}
}
return new_head;
}
以上是我总结的一些例题,如果后面继续碰到其他的题目,我将继续补充。另外还有一些建议,在写完每个函数之后,我们最好可以测试一下,这样可以减少后期解决问题的工作量。
下面是我的测试函数
#include"linklist.h"
#include<stdio.h>
#include<stdlib.h>
#include<stddef.h>
void TestInit(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
printf("phead = %p\n",phead);
}
void TestPushBack(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPrintChar(phead," 尾部插入");
LinkListPopBack(&phead);
LinkListPrintChar(phead," 尾部删除 ");
}
void TestLinkListPushFront(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPrintChar(phead," 尾部插入 ");
LinkListPushFront(&phead,'x');
LinkListPrintChar(phead," 头部插入 ");
LinkListPopFront(&phead);
LinkListPrintChar(phead," 头部删除 ");
}
void TestLinkListFind(){
TestType;
LinkNode* phead;
LinkNode* cur;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPushBack(&phead,'e');
LinkListPrintChar(phead," 插入五个元素 ");
cur = LinkListFind(phead,'d');
printf("要查找的元素位于[%p]\n",cur);
}
void TestLinkListInsert(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListInsert(&phead,phead,'x');
LinkListPrintChar(phead," 对空链表插入 ");
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPushBack(&phead,'e');
LinkListPrintChar(phead," 尾部插入五个元素 ");
LinkListInsert(&phead,NULL,'y');
LinkListPrintChar(phead," pos = NULL ");
LinkListInsert(&phead,phead,'z');
LinkListPrintChar(phead," pos = phead ");
LinkNode* pos = LinkListFind(phead,'c');
LinkListInsert(&phead,pos,'m');
LinkListPrintChar(phead," c位置插入m ");
}
void TestLinkListInsertAfter(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListInsertAfter(&phead,phead,'x');
LinkListPrintChar(phead," 对空链表插入 ");
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPushBack(&phead,'e');
LinkListPrintChar(phead," 尾部插入五个元素 ");
LinkListInsertAfter(&phead,NULL,'y');
LinkListInsertAfter(&phead,phead,'z');
LinkListPrintChar(phead," pos = phead ");
LinkNode* pos = LinkListFind(phead,'c');
LinkListInsertAfter(&phead,pos,'m');
LinkListPrintChar(phead," c位置插入m ");
}
void TestLinkListErase1(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkNode* pos = LinkListFind(phead,'d');
LinkListErase1(&phead,phead);
LinkListPrintChar(phead," 删除头节点 ");
LinkListErase1(&phead,pos);
LinkListPrintChar(phead," 删除d元素 ");
}
void TestLinkListErase2(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPrintChar(phead," 尾插四个元素 ");
LinkNode* posa = LinkListFind(phead,'a');
LinkNode* posd = LinkListFind(phead,'d');
LinkListErase2(&phead,&posa);
LinkListPrintChar(phead," 删除a元素 ");
LinkListErase2(&phead,&posd);
LinkListPrintChar(phead," 删除d元素 ");
}
void TestLinkListRemove(){
TestType;
LinkNode* phead;
int empty;
size_t count;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPrintChar(phead," 尾插四个元素 ");
empty = LinkListEmpty(phead);
printf("empty = [%d]\n",empty);
count = LinkListSize(phead);
printf("数组长度为:%zu\n\n",count);
LinkListRemove(&phead,'c');
LinkListPrintChar(phead," 删除元素c ");
}
void TestLinkListRemoveAll(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'b');
LinkListPrintChar(phead," 尾部插入元素 ");
LinkListRemoveAll(&phead,'b');
LinkListPrintChar(phead," 删除所有的b ");
}
void TestLinkListPrintReverse(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPrintChar(phead," 尾部插入元素 ");
LinkListPrintReverse(phead);
printf("\n");
}
void TestLinkListErase3(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkNode* pos = LinkListFind(phead,'a');
LinkListErase3(&phead,&pos);
LinkListPrintChar(phead,"删除元素a");
LinkNode* pos2 = LinkListFind(phead,'d');
LinkListErase3(&phead,&pos2);
LinkListPrintChar(phead,"删除元素d");
}
void TestLinkListInsertSp(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkNode* pos = LinkListFind(phead,'a');
LinkListInsertSp(&phead,pos,'e');
LinkListPrintChar(phead,"a元素前插入e");
}
void TestJoseCycle(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPushBack(&phead,'e');
LinkListPushBack(&phead,'f');
LinkListPushBack(&phead,'g');
LinkListPushBack(&phead,'h');
LinkNode* cur = phead;
while( cur->next != NULL ){
cur = cur->next;
}
cur->next = phead;
LinkNode* pos = JoseCycle(phead,5);
printf("运行结果:%c\t预期结果:c\n",pos->data);
}
void TestLinkListReverse(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPushBack(&phead,'e');
LinkListReverse(&phead);
LinkListPrintChar(phead,"逆置链表");
}
void TestLinkListBubble(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'d');
LinkListPushBack(&phead,'e');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'f');
LinkListPushBack(&phead,'a');
LinkListBubble(phead);
LinkListPrintChar(phead,"链表排序");
}
void TestLinkListMerge(){
TestType;
LinkNode* phead1;
LinkNode* phead2;
LinkListInit(&phead1);
LinkListInit(&phead2);
LinkListPushBack(&phead1,'b');
LinkListPushBack(&phead1,'d');
LinkListPushBack(&phead1,'f');
LinkListPushBack(&phead1,'h');
LinkListPushBack(&phead1,'j');
LinkListPushBack(&phead1,'l');
LinkListPushBack(&phead2,'a');
LinkListPushBack(&phead2,'c');
LinkListPushBack(&phead2,'e');
LinkListPushBack(&phead2,'g');
LinkListPushBack(&phead2,'i');
LinkListPushBack(&phead2,'k');
LinkListPrintChar(phead1,"链表一");
LinkListPrintChar(phead2,"链表二");
LinkNode* phead = LinkListMerge(phead1,phead2);
LinkListPrintChar(phead,"合并后的链表");
}
void TestLinkListFindMid(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'d');
LinkListPushBack(&phead,'e');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'m');
LinkNode* pos = LinkListFindMid(phead);
printf("expect:c actual:%c\n",pos->data);
}
void TestLinkListFindKth(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'d');
LinkListPushBack(&phead,'e');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'m');
LinkNode* pos = LinkListFindKth(phead,4);
printf("expect:e actual:%c\n",pos->data);
}
void TestLinkListEraseKth(){
TestType;
LinkNode* phead;
LinkListInit(&phead);
LinkListPushBack(&phead,'a');
LinkListPushBack(&phead,'b');
LinkListPushBack(&phead,'c');
LinkListPushBack(&phead,'d');
LinkListPushBack(&phead,'e');
LinkListPushBack(&phead,'f');
LinkListPushBack(&phead,'g');
LinkListPushBack(&phead,'h');
LinkListPushBack(&phead,'i');
LinkListPrintChar(phead,"初始链表");
LinkListEraseKth(&phead,1);
LinkListPrintChar(phead,"删除元素i");
LinkListEraseKth(&phead,4);
LinkListPrintChar(phead,"删除元素e");
LinkListEraseKth(&phead,7);
LinkListPrintChar(phead,"删除元素a");
LinkListEraseKth(&phead,15);
}
void TestLinkListHasCycle(){
TestType;
LinkNode* phead1;
LinkNode* phead2;
LinkNode* a;
LinkNode* b;
LinkListInit(&phead1);
LinkListInit(&phead2);
LinkListPushBack(&phead1,'a');
LinkListPushBack(&phead1,'b');
LinkListPushBack(&phead1,'c');
LinkListPushBack(&phead1,'d');
LinkListPushBack(&phead1,'e');
LinkListPushBack(&phead1,'f');
LinkNode* cur = phead1;
while(cur->next != NULL){
cur = cur->next;
}
cur->next = phead1;
LinkListPushBack(&phead2,'a');
LinkListPushBack(&phead2,'b');
LinkListPushBack(&phead2,'c');
LinkListPushBack(&phead2,'d');
LinkListPushBack(&phead2,'e');
LinkListPushBack(&phead2,'f');
a = LinkListHasCycle(phead1);
b = LinkListHasCycle(phead2);
printf("actual:%p\n\n",a);
printf("actual:%p\n",b);
}
void TestLinkListCycleSize(){
TestType;
LinkNode* phead1;
LinkNode* phead2;
size_t size1 = 0;
size_t size2 = 0;
LinkListInit(&phead1);
LinkListInit(&phead2);
LinkListPushBack(&phead1,'a');
LinkListPushBack(&phead1,'b');
LinkListPushBack(&phead1,'c');
LinkListPushBack(&phead1,'d');
LinkListPushBack(&phead1,'e');
LinkListPushBack(&phead1,'f');
LinkNode* cur = phead1;
while(cur->next != NULL){
cur = cur->next;
}
LinkNode* pos_c = LinkListFind(phead1,'c');
cur->next = pos_c;
LinkListPushBack(&phead2,'a');
LinkListPushBack(&phead2,'b');
LinkListPushBack(&phead2,'c');
LinkListPushBack(&phead2,'d');
LinkListPushBack(&phead2,'e');
LinkListPushBack(&phead2,'f');
size1 = LinkListCycleSize(phead1);
size2 = LinkListCycleSize(phead2);
printf("%zu\n",size1);
printf("%zu\n",size2);
}
void TestLinkListCycleEntryPos(){
TestType;
LinkNode* phead1;
LinkNode* phead2;
LinkListInit(&phead1);
LinkListInit(&phead2);
LinkListPushBack(&phead1,'a');
LinkListPushBack(&phead1,'b');
LinkListPushBack(&phead1,'c');
LinkListPushBack(&phead1,'d');
LinkListPushBack(&phead1,'e');
LinkListPushBack(&phead1,'f');
LinkNode* cur = phead1;
while(cur->next != NULL){
cur = cur->next;
}
LinkNode* pos_c = LinkListFind(phead1,'c');
cur->next = pos_c;
LinkNode* Entry = LinkListCycleEntryPos(phead1);
printf("expect:%p actual:%p\n",pos_c,Entry);
}
void TestLinkListHasCyclePos(){
TestType;
LinkNode* phead1;
LinkNode* phead2;
LinkListInit(&phead1);
LinkListInit(&phead2);
LinkListPushBack(&phead1,'a');
LinkListPushBack(&phead1,'b');
LinkListPushBack(&phead1,'c');
LinkListPushBack(&phead1,'d');
LinkListPushBack(&phead1,'e');
LinkListPushBack(&phead1,'f');
LinkNode* cur1 = phead1;
while(cur1->next != NULL){
cur1 = cur1->next;
}
LinkNode* pos_c = LinkListFind(phead1,'c');
cur1->next = pos_c;
LinkListPushBack(&phead2,'g');
LinkListPushBack(&phead2,'h');
LinkListPushBack(&phead2,'i');
LinkNode* cur2 = phead2;
while(cur2->next != NULL){
cur2 = cur2->next;
}
LinkNode* pos_b = LinkListFind(phead1,'b');
cur2->next = pos_b;
LinkNode* pos_x = LinkListHasCyclePos(phead1,phead2);
printf("\n ******************* 交点在环外 ***********************\n");
printf("expect:%p actual:%p\n",pos_b,pos_x);
LinkNode* pos_d = LinkListFind(phead1,'d');
cur2->next = pos_d;
LinkNode* pos_y = LinkListHasCyclePos(phead1,phead2);
LinkNode* Entry = LinkListCycleEntryPos(phead1);
printf("\n ******************* 交点在环内 ***********************\n");
printf("expect:%p actual:%p\n",Entry,pos_y);
cur1->next = NULL;
cur2->next = NULL;
LinkNode* pos_z = LinkListHasCyclePos(phead1,phead2);
printf("\n ******************* 两个无环交点不相交 ***********************\n");
printf("expect:NULL actual:%p\n",pos_z);
LinkNode* pos_e = LinkListFind(phead1,'e');
cur2->next = pos_e;
LinkNode* pos_m = LinkListHasCyclePos(phead1,phead2);
printf("\n ******************* 两个无环交点相交 ***********************\n");
printf("expect:%p actual:%p\n",pos_e,pos_m);
}
void TestUnionSet(){
TestType;
LinkNode* phead1;
LinkNode* phead2;
LinkListInit(&phead1);
LinkListInit(&phead2);
LinkListPushBack(&phead1,'a');
LinkListPushBack(&phead1,'b');
LinkListPushBack(&phead1,'c');
LinkListPushBack(&phead1,'d');
LinkListPushBack(&phead1,'e');
LinkListPushBack(&phead1,'f');
LinkListPushBack(&phead2,'d');
LinkListPushBack(&phead2,'e');
LinkListPushBack(&phead2,'f');
LinkListPushBack(&phead2,'g');
LinkListPushBack(&phead2,'h');
LinkNode* new_head = UnionSet(phead1,phead2);
LinkListPrintChar(new_head,"查找相同数据");
}
int main(){
TestInit();
TestPushBack();
TestLinkListPushFront();
TestLinkListFind();
TestLinkListInsert();
TestLinkListInsertAfter();
TestLinkListErase1();
TestLinkListErase2();
TestLinkListRemove();
TestLinkListRemoveAll();
TestLinkListPrintReverse();
TestLinkListErase3();
TestLinkListInsertSp();
TestJoseCycle();
TestLinkListReverse();
TestLinkListBubble();
TestLinkListMerge();
TestLinkListFindMid();
TestLinkListFindKth();
TestLinkListEraseKth();
TestLinkListHasCycle();
TestLinkListCycleSize();
TestLinkListCycleEntryPos();
TestLinkListHasCyclePos();
TestUnionSet();
printf("\n\n\n");
return 0;
}
另外,头文件和Makefile奉上。
//linklist.h
#pragma once
#include<stddef.h>
#define TestType printf("\n*************************%s*****************************\n",__FUNCTION__);
typedef char LinkNodeType;
typedef struct LinkNode{
LinkNodeType data;
struct LinkNode* next;
}LinkNode;
void LinkListPrintReverse(LinkNode* phead);
void LinkListErase3(LinkNode** phead,LinkNode** pos);
void LinkListInsertSp(LinkNode** phead, LinkNode* pos, LinkNodeType value);
LinkNode* JoseCycle(LinkNode* phead,size_t food);
void LinkListReverse(LinkNode** phead);
void LinkListBubble(LinkNode* phead);
LinkNode* LinkListMerge(LinkNode* phead1,LinkNode* phead2);
LinkNode* LinkListFindMid(LinkNode* phead);
LinkNode* LinkListFindKth(LinkNode* phead,size_t k);
LinkNode* LinkListHasCycle(LinkNode* phead);
size_t LinkListCycleSize(LinkNode* phead);
LinkNode* LinkListCycleEntryPos(LinkNode* phead);
LinkNode* LinkListHasCyclePos(LinkNode* phead1,LinkNode* phead2);
LinkNode* LinkListHasCyclePos(LinkNode* phead1,LinkNode* phead2);
LinkNode* UnionSet(LinkNode* phead1,LinkNode* phead2);
//Makefile
linklist:linklist.c main.c
gcc $^ -o $@ -g
.PHONY:clean
clean:
rm linklist
由于个人能力有限,以上的说明可能有Bug或者有什么不妥之处,欢迎发邮件到我的邮箱( Cyrus_wen@163.com )批评指正!