单链表是学习不可缺少的一个重要模块,在面试中也会出很多的单链表变种问题,今天就把他们汇总宋总结一下
首先来是实现一个简单的单链表:
(在这里,一些简单的实现单链表的操作函数就不备注了)
typedef int DataType;//typedef了一个类型,以后如果想要改变单链表节点内储存数据的类型就可以直接在这里改变 typedef struct SListNode { DataType data; //数据 struct SListNode* next; //指向下一个节点的指针 }SListNode; SListNode* BuyNode(DataType x)//创建单链表的节点 { SListNode* temp; temp = (SListNode*)malloc(sizeof(SListNode));//为节点开辟一定大小的空间 temp->data = x; temp->next = NULL; return temp; } void PushBack(SListNode* & pHead, DataType x) //在单链表末尾插入数据,这时要检查单链表为空和不为空的两种情况,分别处理 { //1.空 //2.不空 if (pHead == NULL) { pHead = BuyNode(x); } else { SListNode* Tail = pHead; while (Tail->next != NULL) { Tail = Tail->next; } Tail->next = BuyNode(x); } } void PopBack(SListNode* & pHead) //删除单链表末尾的节点 { //1.空 //2.一个节点 //3.多节点 if (pHead == NULL) { printf("The SList is empty\n"); return; } else if (pHead->next == NULL) { free(pHead); pHead = NULL; } else { SListNode* tail = pHead; SListNode* prev = NULL; while (tail->next != NULL) { prev = tail; tail = tail->next; } free(tail); prev->next = NULL; } } //在单链表前面插入一个节点 void PushFront(SListNode* & pHead, DataType x) { //1.空 //2.不空 if (pHead == NULL) { pHead = BuyNode(x); } else if (pHead != NULL) { SListNode* cur = BuyNode(x); cur->next = pHead; pHead = cur; } } //在单链表前面删除一个节点 void PopFront(SListNode* & pHead) { if (pHead == NULL) { return; } else if (pHead->next == NULL) { free(pHead); pHead = NULL; } else if (pHead != NULL) { SListNode* cur = pHead; pHead = pHead->next; free(cur); cur = NULL; } } //查找节点并返回它 SListNode* Find(SListNode* pHead, DataType x) { SListNode* cur = pHead; while (cur) { if (cur->data == x) { return cur; } cur = cur->next; } return NULL; } //在指定位置插入一个节点 void Insert(SListNode* pos, DataType x) { assert(pos); SListNode* temp = BuyNode(x); temp->next = pos->next; pos->next = temp; } //删除指定节点 void Erase(SListNode* pHead,SListNode* pos) { assert(pos); assert(pHead); if (pHead == pos) { pHead = pHead->next; free(pos); pos = NULL; } SListNode* prev = pHead; while (prev) { if (prev->next == pos) { prev->next = pos->next; free(pos); pos = NULL; break; } prev = prev->next; } } //队单链表冒泡排序,(只改变单链表结点的数据) void Bubble(SListNode* pHead) { int exange = 0; if (pHead == NULL || pHead->next == NULL) { return; } SListNode* prev = pHead; SListNode* cur = pHead->next; SListNode* Tail =NULL;
while (Tail != pHead) { cur = pHead->next; prev = pHead; while (cur != Tail) { if (prev->data > cur->data)//比较节点信息,如果满足条件就交换它 { DataType x; x = cur->data; cur->data = prev->data; prev->data = x; } prev = cur; cur = cur->next;//指向下一个节点,实现迭代 } Tail = prev;//循环结束后prev指向为节点,赋值给Tail } } //删除一个无头单链表的非尾节点,思想就是交换该节点和下一个节点的信息,删除该节点的后一个节点 void DelNonTailNode(SListNode* pos) { assert(pos); assert(pos->next); SListNode* del = pos->next; pos->data = del->data; pos->next = del->next; free(del); del = NULL; } //在无头单链表的非头节点插入一个节点 void InsertNonTailNode(SListNode* pos,DataType x) { assert(pos); SListNode* cur = BuyNode(pos->data); SListNode* temp = pos->next; cur->next = temp; pos->next = cur; pos->data = x; } //查找单链表的中间节点并只能遍历一次链表(快慢指针) //快指针走两步满指针走一步,等到快指针走到尾,则慢指针刚好到中间 SListNode* FindMidNode(SListNode* pHead) { assert(pHead); if (pHead->next == NULL) { return pHead; } else { SListNode* slow = pHead; SListNode* fast = pHead; //在这里我给出了两种写法,都是正确的 /*while (fast)//快指针不为空,在下面条件判断快指针的下一个节点也不为空 { if (fast->next) { fast = fast->next->next; } else { break; } slow = slow->next; }*/ while (fast && fast->next)//注意这里的条件是快指针和快指针的下一个节点都不为空 { slow = slow->next; fast = fast->next->next; } return slow;//返回慢节点,也就是中间节点 } return NULL; } //查找链表的倒数第k个节点,且只能遍历链表一次 //这也是利用快慢指针,快指针先走k步,慢指针走一步,快指针走一步,则两个指针相差k步,当快指针指向空时,慢指针刚好指向倒数第k个节点 SListNode* FindNode(SListNode* pHead, int k) { assert(pHead); assert(k >= 0); SListNode* slow = pHead; SListNode* fast = pHead; //有问题 /*while (fast && fast->next) { while (k--) { fast = fast->next; } fast = fast->next; slow = slow->next; }*/ while (fast && --k) { fast = fast->next; if (fast == NULL) { return NULL; } } while (fast->next) { fast = fast->next; slow = slow->next; } return slow; } //从尾到头打印单链表(利用递归实现) void PrintTailToHead(SListNode* pHead) { if (pHead == NULL) { return; } else { PrintTailToHead(pHead->next); printf("%d ", pHead->data); } } //逆置单链表 很重要,创建新的头节点,把单链表的每个节点摘下来插入
它前面,再把它往前挪构成一个新的单链表,返回新链表的头节点 SListNode* Reverse(SListNode* pHead) { SListNode* cur = pHead; SListNode* newHead = NULL; while (cur) { SListNode* temp = cur; cur = cur->next; temp->next = newHead; newHead = temp; } return newHead; } //单链表实现约瑟夫环 //运行时先构造环,注意在代码结尾解环 SListNode* JosePhCycle(SListNode* pHead, int m) { SListNode* cur = pHead; while (1) { if (cur == NULL) { return NULL; } else if (cur == cur->next)//只剩一个节点 { return cur; } else { int x = m; while (--x)//指向第m各节点并删除它,循环程序直到只剩一个节点的时候返回它 { cur = cur->next; } SListNode* del = cur->next; cur->data = del->data; cur->next = del->next; free(del);//释放节点并置空 del = NULL; } } } //合并两个有序链表,合并后依然有序,摘下一个节点,比较大小插入到新链表的尾部,构成一个新的单链表,返回新链表的头节点 SListNode* Meragelist(SListNode* pHead1, SListNode* pHead2) { if (pHead1 == NULL) { return pHead2; } if (pHead2 == NULL) { return pHead1; } //SListNode* newHead = pHead1->data < pHead2->data ? pHead1:pHead2; //while (pHead1 == NULL || pHead2 == NULL) //{ //if (pHead1->data < pHead2->data) //{ //newHead = pHead1; //pHead1 = pHead1->next; //} //else if (pHead1->data == pHead2->data) //{ //newHead = pHead1; //newHead->next = pHead2; //pHead1 = pHead1->next; //pHead2 = pHead2->next; //} //else //{ //newHead = pHead2; //pHead2 = pHead2->next; //} //newHead = newHead->next; //newHead->next = NULL; //} //while (pHead1) //{ //newHead->next = pHead1; //pHead1 = pHead1->next; //} //while (pHead2) SListNode* newHead = NULL; SListNode* cur1 = pHead1; SListNode* cur2 = pHead2; if (cur1->data < cur2->data) { newHead = cur1; cur1 = cur1->next; } SListNode* Tail = newHead; while (cur1 && cur2) { if (cur1->data < cur2->data) { Tail->next = cur1; cur1 = cur1->next; } else { Tail->next = cur2; cur2 = cur2->next; } Tail = Tail->next; Tail->next = NULL; } if (cur1 != NULL) { Tail->next = cur1; } if (cur2 != NULL) { Tail->next = cur2; } return newHead; } /判断链表是否带环(可以用快慢指针解决),快指针走两步,慢指针走一步,看看是否会相遇,相遇了则是带环,不想与则不带环 bool IsSListCycle(SListNode* pHead) { if (pHead == NULL) { printf("The SList is
empty\n"); return false; } SListNode* slow = pHead; SListNode* fast = pHead; while (fast && fast->next) { fast = fast->next->next; slow = slow->next; if (fast == slow) { SListNode* cur = slow; int length = 0; //环的长度 do { slow = slow->next; length++; } while (cur != slow); printf("%d\n", length); printf("The SList have cycle\n"); return true; } } printf("The SList NO cycle\n"); return false; } //环的入口点 SListNode* CycleEntry(SListNode* pHead) { if (pHead == NULL) { printf("The SList is empty\n"); return NULL; } SListNode* slow = pHead; SListNode* fast = pHead; while (fast && fast->next) { fast = fast->next->next; slow = slow->next; if (fast == slow) { return slow; } } } //链表是否相交,若相交,求交点(不带环)指向同一个节点,并不是相同信息的节点 SListNode* IsItersect(SListNode* pHead1,SListNode* pHead2) { if (pHead1 == NULL) { printf("链表不相交\n"); return pHead2; } if (pHead2 == NULL) { printf("链表不相交\n"); return pHead1; } SListNode* cur1 = pHead1; SListNode* cur2 = pHead2; while (cur1 && cur2) { if (cur1 == cur2) { printf("链表相交,交点为:%d\n", cur1->data); return cur1; } cur1 = cur1->next; cur2 = cur2 ->next; } return NULL; }
时间: 2024-11-16 23:14:40