#pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<memory.h> #define DataType int //int 可以改写为其它数据类型 typedef struct Node { DataType data; struct Node *next; }Node,*pNode; //定义结点结构体 //建立带头结点的单链表时传参数时一定要对头结点是否为空进行断言// /***************************************************************************************/ void InitLinkList(pNode *pHead); //初始化单链表 void PushBack(Node *pHead,DataType x); //尾部增加一个结点 void PushBackRing(Node *pHead,DataType x); //在尾部增加一个结点并连接成环 void PushBefore(Node *pHead,DataType x); //表头增加一个结点 void PushMid(Node *pHead,DataType x,DataType y); //在某个元素 x 之后插入 y void PopBefore(Node *pHead); //头删法 void PopBack(Node *pHead); //尾删法 void PopMid(Node *pHead,DataType x); //删除元素 x 之后的元素 Node* Found(Node *pHead,DataType x); //查找某一个元素 x void TraveLinkList(Node *pHead); //遍历单链表 void Back_Printf(Node *pHead); //运用递归逆序输出 void Delete_note_noHead(Node *Some_Node); //删除不带头结点的非尾节点 void Insert_note_noHead(Node *Some_Node,DataType x); //不带头结点的单链表中在某个结点前插入一个结点 void Josephus_problem(Node *pHead,int n); //用循环单链表实现约瑟夫环的问题 void Swap(int& a,int& b); //用引用方式交换两个整数 void Bubble_Sort(Node* pHead); //单链表的冒泡排序 Node* Combine(Node *pHead_One,Node *pHead_Two); //合并两个升序的单链表 Node* MiddleNode(Node *pHead); //遍历一次寻找单链表的中间结点 Node* Last_N_Of_Linklist(Node* pHead,DataType x); //遍历一次找到倒数第n个结点 Node* Judge_Ring(Node* pHead); //利用快慢指针方法判断单链表是否带环 Node* Judge_Across(Node* pHead_One,Node* pHead_Two); //判断两个链表(不带环)是否相交,如果相交找出交点 Node* Judge_Across_Add(Node* pHead_One,Node* pHead_Two); //判断两个链表是否相交(可能带环) //如果相交找出交点(返回交点结点的地址) Node* Judge_Ring_Update(Node* pHead); //判断一个链表是否带环,并求出换大小和入口结点 Node* Judge_Cross_Update(Node* pHead_One,Node* pHead_Two); //判断两个单链表是否相交的更新版本 /***************************************************************************************/
#include"LinkList.h" void InitLinkList(pNode *pHead) //初始化单链表 { assert(pHead); (*pHead) = (Node*)malloc(sizeof(Node)); (*pHead)->next = NULL; } void PushBack(Node *pHead,DataType x) //尾部增加一个结点 { Node *p = pHead; Node *pnode = (Node*)malloc(sizeof(Node)); pnode->data = x; while(p->next) { p=p->next; } p->next = pnode; pnode->next = NULL; } void PushBackRing(Node *pHead,DataType x) //在尾部增加一个结点并连接成环 { Node *p = pHead; Node *pnode = (Node*)malloc(sizeof(Node)); pnode->data = x; while(p->next) { p=p->next; } p->next = pnode; pnode->next = pHead->next->next; } void PushBefore(Node *pHead,DataType x) //表头增加一个结点 { Node *p = pHead->next; Node *pnode = (Node*)malloc(sizeof(Node)); pnode->data = x; pnode->next = pHead->next; pHead->next = pnode; } void PushMid(Node *pHead,DataType x,DataType y) //在某个元素 x 之后插入 y { if(Found(pHead,x)) { Node *p = Found(pHead,x); Node *pnode = (Node*)malloc(sizeof(Node)); pnode->data = y; pnode->next = p->next; p->next = pnode; } else { printf("Error:No Found The Number\n"); } } void TraveLinkList(Node *pHead) //遍历单链表 { assert(pHead); Node *p = pHead->next; while(p) { printf("%d -> ",p->data); p = p->next; } printf("NULL\n"); } void PopBefore(Node *pHead) //头删法 { if(pHead->next == NULL) { printf("Error:This LinkList is Empty!\n"); return; } Node *p = pHead->next; pHead->next = p->next; free(p); p = NULL; } void PopBack(Node *pHead) //尾删法 { if(pHead->next == NULL) { printf("Error:This LinkList is Empty!\n"); return; } Node *p1; Node *p2 = pHead->next; while(p2->next) { p1 = p2; p2 = p2->next; } p1->next = NULL; free(p2); p2 = NULL; } void PopMid(Node *pHead,DataType x) //删除元素 x 之后的元素 { if(Found(pHead,x)) { Node *p = Found(pHead,x); Node *pnode = p->next;; p->next = pnode->next; free(pnode); pnode = NULL; } else { printf("Error:No Found The Number\n"); } } Node* Found(Node *pHead,DataType x) //查找某一个元素 x { if(pHead->next == NULL) { printf("Error:This LinkList is Empty!\n"); return NULL; } Node *p = pHead->next; while(p) { if(p->data == x) { return p; } p = p->next; } return NULL; } void ReplaceLinkList(Node *pHead) //单链表的逆置 { if(pHead->next == NULL) { printf("Error:This LinkList is Empty!\n"); return ; } Node *pnode = pHead->next; pHead->next = NULL; while(pnode) { Node *p = pnode; pnode = pnode->next; //指针后移一位 p->next = pHead->next; //在头结点之后插入一个值之后 pHead->next = p; } } void Back_Printf(Node *pHead) //运用递归逆序输出 { if(pHead->next) { Back_Printf(pHead->next); } printf("%d -> ",pHead->data); } void Delete_note_noHead(Node *Some_Node) //删除不带头结点的非尾节点 { Some_Node->data = Some_Node->next->data; Node* pNode = Some_Node->next; Some_Node->next = Some_Node->next->next; free(pNode); } void Insert_note_noHead(Node *Some_Node,DataType x) //不带头结点的单链表中在某个结点前插入一个结点 { Node* pNode = (Node*)malloc(sizeof(Node)); pNode->next = Some_Node->next; Some_Node->next = pNode; pNode->data = Some_Node->data; Some_Node->data = x; } void Josephus_problem(Node *pHead,int n) //用循环单链表实现约瑟夫环的问题 { Node* pNode = pHead->next; while(pNode->next != pNode) //如果链表中只剩一个结点,则输出这个节点的值 { for(int i=0; i<n-1; ++i) { pNode = pNode->next; } printf("%d -> ",pNode->data); Node* Delete_Node = pNode->next; //用一个节点保存pNode的下一个节点 pNode->data = pNode->next->data; //将下一个节点的数据保存在pNnode中 pNode->next = pNode->next->next; //删除下一个节点,当前指针指向pNode结点 free(Delete_Node); //此方法相当于删除了当前结点,而指针指向了下一个结点 } printf("%d -> ",pNode->data); } void Swap(int& a,int& b) //用引用方式交换两个整数 { int tmp = a; a = b; b = tmp; } void Bubble_Sort(Node* pHead) //优化后的单链表的冒泡排序 { if(pHead->next == NULL || pHead->next->next == NULL) { return ; } else { Node* pLeft = pHead->next; Node* pRight = pHead->next->next; Node* pTail = NULL; int num = 0; while( pRight != pTail ) //整体结束的标志是一趟开始就 pRight遇到 pTail { while( pRight != pTail ) //每一趟的结束标志是 pRight 遇到 pTail { if(pLeft->data > pRight->data) { Swap(pLeft->data,pRight->data); num++; } pLeft = pLeft->next; pRight = pRight->next; } if(num == 0 ) //如果那一趟比较下来没有交换的数说明已经排好了 { //故退出 return; } pTail = pLeft; //每一趟比较完成将 pTail 指针向前移一位 pLeft = pHead->next; //pLeft指向第一个节点 pRight = pHead->next->next; //pRight指向第二个节点 } } } Node* Combine(Node *pHead_One,Node *pHead_Two) //合并两个升序的单链表 { if(pHead_One->next==NULL || pHead_Two->next==NULL) //如果其中一个链表为空则返回另一个 { //单链表的头结点 return (pHead_One->next==NULL)?(pHead_One=pHead_Two):pHead_One; } else { Node* pHead_One_Copy = pHead_One; Node* pNode_One = pHead_One->next; Node* pNode_Two = pHead_Two->next; Node *pNode; while(pNode_One!=NULL && pNode_Two!=NULL) { if(pNode_One->data > pNode_Two->data) //如果链表二的数小 { pNode = pNode_Two; pNode_Two = pNode_Two->next; //链表二中的指针后移 pHead_One_Copy->next = pNode; //将链表二中的数增添入新链表中 pHead_One_Copy = pHead_One_Copy->next; // pHead_One_Copy指向链表尾部 } else { //如果链表一的数小 pNode = pNode_One; pNode_One = pNode_One->next; //链表一中的指针后移 pHead_One_Copy->next = pNode; //将链表一中的数增添入新链表中 pHead_One_Copy = pHead_One_Copy->next; // pHead_One_Copy指向链表尾部 } } (pNode_One == NULL)?(pHead_One_Copy->next = pNode_Two) :(pHead_One_Copy->next = pNode_One); //如果pNode_One == NULL 将 pNode_Two 指向的结点及其之后的结点接在新链表后,否则 //将 pNode_One 指向的结点及其之后的结点接在新链表后 return pHead_One; } } Node* MiddleNode(Node *pHead) //遍历一次寻找单链表的中间结点 { if(pHead->next == NULL) { return NULL; } Node *pNodeFast = pHead->next; Node *pNodeLow = pHead->next; while(pNodeFast!=NULL && pNodeFast->next!=NULL) { pNodeFast = pNodeFast->next->next; pNodeLow = pNodeLow->next; } return pNodeLow; } Node* Last_N_Of_Linklist(Node* pHead,DataType x) //遍历一次找到倒数第n个结点 { if(pHead->next == NULL) { printf("Error:This LinkList Is Empty!\n"); return NULL; } Node* pNodeLeft = pHead->next; Node* pNodeRight = pHead->next; int nodes = x; while(--x) //将右指针向后移动 x-1 个结点 { pNodeRight = pNodeRight->next; if(pNodeRight == NULL) //如果在移动过程中 pNodeRight 到尾部了说明 { //次单链表的结点数小于 x 个,故倒数第 x 个不存在 printf("Error:This LinkList Less Than %d !\n",nodes); return NULL; } } while(pNodeRight->next) //左右指针同时往后移动直到右指针指向了尾部 { pNodeLeft = pNodeLeft->next; pNodeRight = pNodeRight->next; } return pNodeLeft; } Node* Judge_Ring(Node* pHead) //利用快慢指针方法判断单链表是否带环 { if(pHead->next == NULL) { printf("Error:This LinkList Is Empty!\n"); return NULL; } Node* pNodeFast = pHead->next; Node* pNodeLow = pHead->next; Node* pEntrance = pHead->next; while( pNodeFast && pNodeFast->next) //循环结束条件(如果条件成立则pNodeFast最大可能倒数第二个) { //防止了以 pNodeFast->next 为结束条件时的, pNodeFast = pNodeFast->next->next; //pNodeFast->next->next == NULL 在 while() pNodeLow = pNodeLow->next; //条件判断时 NULL->next 程序崩溃的情况 if(pNodeFast == pNodeLow) { printf("\n此单链表为带环单链表\n"); pNodeLow = pNodeLow->next; int nodes = 1; //如果是带环单链表则求环的长度 while(pNodeFast != pNodeLow) { pNodeLow = pNodeLow->next; nodes++; } printf("\n此单链表中环的长度为 %d\n",nodes); while(1) //查找环的入口地址 { int num = 1; Node* pNode = pEntrance; //假如pEntrance是入口 while(nodes--) { pNode = pNode->next; } if(pEntrance == pNode) //则pEntrance的后面第nodes-1个就是它自己 { printf("\n此循环单链表循环的入口在第 %d 个节点\n",num); return pEntrance; //如果找到了则返回环入口节点的地址 } else { pEntrance = pEntrance->next; num++; } } } } return NULL; } Node* Judge_Across(Node* pHead_One,Node* pHead_Two) //判断两个链表(不带环)是否相交,如果相交找出交点 { if(pHead_One->next ==NULL || pHead_Two->next == NULL) { return NULL; } Node* pNode_One = pHead_One->next; Node* pNode_Two = pHead_Two->next; while(pNode_One) //遍历_One 链表 { Node* pNode = pNode_Two; while(pNode) //遍历_Two 链表 { if(pNode == pNode_One) //如果发现有相同元素,则将这个结点返回 { printf("这两个链表相交!\n"); return pNode; } pNode = pNode->next; } pNode_One = pNode_One->next; } return NULL; } /**************************************************************************************** * 函数名 : Node* Judge_Across_Add(Node* pHead_One,Node* pHead_Two) * 功能描述: 判断两个链表是否相交(可能带环)如果相交找出交点(返回交点结点的地址) * 输入参数: 两个链表的头结点 * 输出参数: 相交结点的指针 * 作者 : 石豪 * 创建日期: 2015/11/23 12:49:16 ****************************************************************************************/ Node* Judge_Across_Add(Node* pHead_One,Node* pHead_Two) //判断两个链表是否相交(可能带环) { //如果相交找出交点(返回交点结点的地址) if(pHead_One->next ==NULL || pHead_Two->next == NULL) { return NULL; } Node* pNode_One = pHead_One->next; Node* pNode_Two = pHead_Two->next; Node* pNode_In_Ring_One = Judge_Ring(pHead_One); Node* pNode_In_Ring_Two = Judge_Ring(pHead_Two); if(pNode_In_Ring_One==NULL && pNode_In_Ring_Two==NULL) //如果两个链表都没有带环 { Judge_Across(pHead_One,pHead_Two); //用此函数判断是否相交 } else if(pNode_In_Ring_One!=NULL && pNode_In_Ring_Two!=NULL) //如果两个链表都带环 { while(pNode_One->next!=pNode_In_Ring_One && pNode_One!=pNode_In_Ring_One) //先判断没有进环的部分有没有相交 { while(pNode_Two->next!=pNode_In_Ring_Two && pNode_Two!=pNode_In_Ring_Two) { if(pNode_One == pNode_Two) { printf("这两个链表在没有进环时相交!\n"); return pNode_One; } pNode_Two = pNode_Two->next; } pNode_One = pNode_One->next; } //如果两个链表都带环且没有进环部分没有相同的,即没有相交 Node *pNode = pNode_In_Ring_Two->next; while(pNode != pNode_In_Ring_Two) //让 pNode_In_Ring_Two 在自己环内走一圈 { //如果遇到了 pNode_In_Ring_One 说明两个链表在 if(pNode == pNode_In_Ring_One) //环内相遇,且交点为 pNode_In_Ring_Two { printf("这两个链表在环内相交!\n"); return pNode_In_Ring_Two; } pNode = pNode->next; } } else //两个链表中只有一个带环,则这两个链表不可能相交 { printf("这两个链表没有相交!\n"); return NULL; } } /************************************************************************************** * 函数名 : Node* Judge_Ring_Update(Node* pHead) * 功能描述: 判断一个链表是否带环,并求出换大小和入口结点 * 输入参数: 单链表头结点 * 输出参数: 单链表的环的入口结点的指针 * 作者 : 石豪 * 创建日期: 2015/11/23 12:36:14 **************************************************************************************/ Node* Judge_Ring_Update(Node* pHead) //判断一个链表是否带环,并求出换大小和入口结点 { assert(pHead); //头结点不能为空 if(pHead->next == NULL) { printf("This LinkList is Empty!\n"); } Node* pNode_Fast = pHead->next; Node* pNode_Low = pHead->next; Node* pNode_In_Ring = pHead->next; int Switch = 0; //这个“开关”很巧妙,如果 pNode_Fast,pNode_Low 都为 pHead->next 时 //有两种情况 0、都没走 1、在pHead->next处相遇 //如果 Switch = 0 说明是第一种情况就不可以进入if语句,反之就可以 while(pNode_Fast && pNode_Fast->next) { if(pNode_Fast == pNode_Low && Switch) { printf("This Linklist is Ring!\n"); //如果两个指针相遇说明链表带环 //在已知带环的情况下求出环的节点数 pNode_Low = pNode_Low->next; int count = 1; while(pNode_Fast != pNode_Low) //让慢指针一次走一步计算出环的节点数 { pNode_Low = pNode_Low->next; count++; } printf("This LinkList‘s Ring Have %d nodes!\n",count); /* 1.利用公式(C*N - X = L)求出入口点 */ /* C -- 环的节点数 N -- 在慢指针进入环之前,快指针已经在环中走的圈数 */ /* X -- 快慢指针相遇点的指针 L -- 在环入口之前的结点个数 */ while(pNode_In_Ring != pNode_Low) { pNode_In_Ring = pNode_In_Ring->next; pNode_Low = pNode_Low->next; } return pNode_In_Ring; //找到入口结点并返回此指针 } pNode_Fast = pNode_Fast->next->next; pNode_Low = pNode_Low->next; Switch = 1; } } /***************************************************************************** * 函数名 : void Judge_Cross_Update(Node* pHead_One,Node* pHead_Two) * 功能描述: 判断两个单链表是否相交的更新版本 * 输入参数: 两个链表的头结点 * 输出参数: 链表交点的指针 * 作者 : 石豪 * 创建日期: 2015/11/23 14:29:51 *****************************************************************************/ Node* Judge_Cross_Update(Node* pHead_One,Node* pHead_Two) { assert(pHead_One && pHead_Two); //带头结点的单链表要进行断言 if( pHead_One->next==NULL || pHead_Two->next==NULL ) { printf("This two linklist haven‘t cross!\n"); return NULL; } Node* Node_One = pHead_One->next; Node* Node_Two = pHead_Two->next; int Count_One = 1,Count_Two = 1; while(Node_One->next) //遍历链表一,并记录链表的长度 { Node_One = Node_One->next; Count_One++; } while(Node_Two->next) //遍历链表二,并记录链表的长度 { Node_Two = Node_Two->next; Count_Two++; } if( Node_One==Node_Two ) { printf("This two linklist have cross point!\n"); Node* pNode_Point_Long; //让 pNode_Point_Long 指针指向较长的那个链表 Node* pNode_Point_Short; //让 pNode_Point_Short 指针指向较短的那个链表 int Gap; //两个链表之间结点数的差值 Count_One > Count_Two ? (pNode_Point_Long = pHead_One->next , pNode_Point_Short = pHead_Two->next) : (pNode_Point_Long = pHead_Two->next , pNode_Point_Short = pHead_One->next); Count_One > Count_Two ? (Gap = Count_One - Count_Two) : (Gap = Count_Two - Count_One); for(int i=0; i<Gap; ++i) //先让指向长链表的指针向后走Gap步 { pNode_Point_Long = pNode_Point_Long->next; } while(pNode_Point_Long != pNode_Point_Short) //再让两个指针同时往后走直到相遇 { pNode_Point_Long = pNode_Point_Long->next; pNode_Point_Short = pNode_Point_Short->next; } return pNode_Point_Long; } else { printf("This two linklist isn‘t cross point!\n"); return NULL; } } void Test1(Node *pHead) { Node *p = Found(pHead,0); //查找 if( p == NULL) { printf("Error:No Found The Number\n"); } else { printf("%d \n",p->data); } } void Test2(Node *pHead) { for(int i=0; i<10; i++) { PushBack(pHead,i); } PushBack(pHead,10); //尾插(√) PushBefore(pHead,9); //头插(√) PopBefore(pHead); //头删(√) PopBack(pHead); //尾删(√) PushMid(pHead,5,11); //在特定位置之后插入(√) PopMid(pHead,5); //在特定位置之后删除(√) TraveLinkList(pHead); //遍历单链表(√) ReplaceLinkList(pHead); //单链表的逆置(√) TraveLinkList(pHead); Test1(pHead); //查找(√) } void Test3(Node *pHead) { for(int i=0; i<10; i++) { PushBack(pHead,i); } TraveLinkList(pHead); //遍历单链表 Back_Printf(pHead->next); printf("\n"); } void Test4(Node *pHead) { for(int i=0; i<10; i++) { PushBack(pHead,i); } TraveLinkList(pHead); //遍历单链表 Node* pNode1 = Found(pHead,5); Insert_note_noHead(pNode1,100); //不带头结点的单链表中在某个结点前插入一个结点(√) TraveLinkList(pHead); //遍历单链表 } void Test5(Node *pHead) //约瑟夫环的问题(√) { for(int i=0; i<10; i++) { PushBack(pHead,i); } PushBackRing(pHead,100); Node* pNode = pHead->next; for(i=0; i<11; ++i) { printf("%d->",pNode->data); pNode = pNode->next; } Judge_Ring(pHead); //判断链表是否带环,如果带环求出环的长度(√) //Josephus_problem(pHead,5); printf("\n"); //TraveLinkList(pHead); //遍历单链表 //TraveLinkList(pHead); //遍历单链表 } void Test6(Node *pHead) //验证链表冒泡排序(√) { for(int i=10; i>0; i--) { PushBack(pHead,i); } for(i=10; i>0; i--) { PushBack(pHead,2*i); } TraveLinkList(pHead); //遍历单链表 Bubble_Sort(pHead); TraveLinkList(pHead); //遍历单链表 } void Test7(Node *pHead_One,Node *pHead_Two) //验证两个升序单链表的合并(√) { for(int i=0; i<5; i++) { PushBack(pHead_One,i*2); } for(i=0; i<5; i++) { PushBack(pHead_Two,i); } TraveLinkList(pHead_One); //遍历单链表 TraveLinkList(pHead_Two); //遍历单链表 Node *pNode = Combine(pHead_One,pHead_Two); //合并两个升序的单链表 TraveLinkList(pNode); } void Test8(Node *pHead) //查找中间节点(√) { for(int i=0; i<10; i++) { //PushBack(pHead,i*2); } TraveLinkList(pHead); //遍历单链表 Node* pNode = MiddleNode(pHead); printf("中间节点为:%d\n",pNode->data); } void Test9(Node *pHead) //查找倒数第x个节点(√) { for(int i=0; i<10; i++) { PushBack(pHead,i*2); } TraveLinkList(pHead); //遍历单链表 Node* pNode = Last_N_Of_Linklist(pHead,11); printf("倒数第11个节点为:%d\n",pNode); } void Test10(Node* pHead_One,Node* pHead_Two) //判断两个链表是否相交(√) { for(int i=10; i>0; i--) { PushBack(pHead_One,i); } pHead_Two->next = pHead_One->next; TraveLinkList(pHead_One); //遍历单链表 TraveLinkList(pHead_Two); //遍历单链表 Node* pNode = Judge_Across(pHead_One,pHead_Two); //判断两个链表(不带环)是否相交,如果相交找出交点(√) printf("%d\n",pNode->data); } void Test11(Node* pHead_One,Node* pHead_Two) { for(int i=0; i<10; i++) { PushBack(pHead_One,i); } PushBackRing(pHead_One,100); pHead_Two->next = pHead_One->next; Judge_Across_Add(pHead_One,pHead_Two); } void Test12(Node *pHead) //求一个链表是否带环问题巧妙方法求解() { for(int i=0; i<10; i++) { PushBack(pHead,i); } PushBackRing(pHead,100); Node* pNode = Judge_Ring_Update(pHead); printf("入口地址为0x%x data域为%d\n",pNode,pNode->data); } void Test13(Node* pHead_One,Node* pHead_Two) { for(int i=0; i<10; i++) { PushBack(pHead_One,i); } for(i=0; i<5; i++) { PushBack(pHead_Two,i); } Node* pNode_One = Found(pHead_One,6); Node* pNode_Two = Found(pHead_Two,4); pNode_Two->next = pNode_One; Node *pNode_Point = Judge_Cross_Update(pHead_One,pHead_Two); //检测两个链表相交更新版本(√) printf("相交结点的地址:0x%x 值为:%d\n",pNode_Point,pNode_Point->data); } void main() { Node *pHead_One; InitLinkList(&pHead_One); //初始化单链表 Node *pHead_Two; InitLinkList(&pHead_Two); //初始化单链表 //Test5(pHead); //Test6(pHead); //Test7(pHead_One,pHead_Two);//合并两个升序的单链表(√) //Test8(pHead); //Test9(pHead); //Test10(pHead_One,pHead_Two);//判断两个链表(不带环)是否相交,如果相交找出交点(√) //Node *pHead; //InitLinkList(&pHead); //初始化单链表 //Test12(pHead); Test13(pHead_One,pHead_Two); //(√) }
本文出自 “10747227” 博客,请务必保留此出处http://10757227.blog.51cto.com/10747227/1716511
原文地址:http://10757227.blog.51cto.com/10747227/1716511