无头节点的单链表
链表是一种线性表,但是并不是顺序存储,而是每个节点里面存储着下一个节点的指针,把存储数据元素的数据串链起来。
链表和顺序表的优缺点
1>.顺序表支持随机访问,单链表不支持随机访问
2>.顺序表插入/删除数据效率很低时间复杂度为0(N);除尾插尾删效率高,时间复杂度为0(1)
3>.单链表CPU高速缓存效率低,顺序表的CPU高速缓存效率更高。(因为顺序表的空间一般是连续开辟的,而且一次会开辟存储多个元素的空间,所以在使用顺序表时,可以一次把多个数据写入 高速缓存,再写入主存,顺序表的CPU高速缓存效率更高,且CPU流水线也不会总是被打断;而单链表是每需要存储一个数据才开辟一次空间,所以每个数据存储时都要单独的写入高速缓存区,再写入主存,这样就造成了,单链表CPU高速缓存效率低,且CPU流水线会经常被打断。)
单链表的数据结构:
typedef int DataType ;
typedef struct Node
{
DataType _data ; // 数据
struct Node* _next; // 指向下一个节点的指针
} Node, *PLinkList ;
下面是对链表的一些操作
//1、链表的初始化,PSListNode *pHead二级指针,对指向的内容做修改也可以用引用 void InitSList(PSListNode *pHead) { *pHead = NULL; } //2、链表的销毁 void DestroyList(PSListNode *pHead) { PSListNode cur = pHead;//先保留指向头结点的指针 while (cur) { PSListNode temp = cur; cur = cur->pNext; free(temp); } pHead = NULL;//置空 } //3、构造出一个新的节点 PSListNode BuyNode(DataType data) { PSListNode temp = (PSListNode)malloc(sizeof(struct SListNode)); assert(temp); temp->data = data; temp->pNext = NULL; return temp; } //尾插(要考虑2种情况,空和非空) void PushBack(PSListNode *pHead, DataType data) { PSListNode tail = *pHead; //空和非空 if (*pHead == NULL) { *pHead = BuyNode(data); } else { while(tail->pNext!=NULL) { tail = tail->pNext; } tail->pNext = BuyNode(data); } } //尾删(3种情况 :空 一个节点 多个节点) void PopBack(PSListNode *pHead) { PSListNode pNode = *pHead; if (*pHead == NULL) { printf("it is empty"); return; } else if(pNode->pNext==NULL) { free(pNode); pHead = NULL; } else { PSListNode tail = *pHead; PSListNode prevtail = NULL; while (tail->pNext) { prevtail = tail; tail = tail->pNext; } prevtail->pNext = NULL; free(tail); } } //头插考虑2种情况(空和非空) void PushFront(PSListNode *pHead,DataType data) { if (NULL == *pHead) { *pHead = BuyNode(data); } else { PSListNode pNode = BuyNode(data); pNode->pNext =*pHead; *pHead = pNode; } } //头删考虑2种情况(空 非空)void PopFront(PSListNode *pHead){ if (NULL == pHead) { return; } else { PSListNode pNode = *pHead; *pHead = pNode->pNext; free(pNode); } } //找节点 PSListNode Find(PSListNode *pHead, DataType data) { PSListNode pNode = *pHead; while (pNode) { if (pNode->data == data) { return pNode; } pNode = pNode->pNext; } return NULL; } //删除指定的节点 void Erase(PSListNode *pHead, PSListNode pos) { assert(NULL != pHead); assert(NULL!=pos); if (pos == *pHead) { *pHead = pos->pNext; free(pos); } else { PSListNode cur = *pHead; while (cur) { if (cur->pNext ==pos) { cur->pNext = pos->pNext; free(pos); break; } cur = cur->pNext; } } } //插入 void Insert(PSListNode *pHead, PSListNode pos, DataType data)//PSListNode pos(指向pos节点的指针) { assert(pos); assert(pHead); if (NULL == *pHead) { return; } PSListNode pNode = BuyNode(data); if (pNode != NULL) { pNode->pNext = pos->pNext; pos->pNext = pNode; } } void PrintListTailToHead(PSListNode pHead) { if (pHead) { PrintListTailToHead(pHead->pNext); printf("%d ", pHead->data); } } void InsertNotHead(PSListNode pos, DataType data) { assert(NULL != pos); PSListNode pNode = BuyNode(pos->data); pNode->pNext = pos->pNext; pos->pNext = pNode; pos->data = data; } void DelNotTailNode(PSListNode pos) { assert(pos && pos->pNext); pos->data = pos->pNext->data; PSListNode*pNode = pos->pNext->pNext; free(pos->pNext); pos->pNext =pNode; } //返回中间节点的指针,2个返回第2个 PSListNode FindMidNode(PSListNode pHead) { PSListNode Slow = pHead; PSListNode Fast = pHead; while ((NULL!=Fast)&&(Fast->pNext!=NULL)///////////************ { Slow = Slow->pNext; Fast = Fast->pNext->pNext; } return Slow; } // 查找链表的倒数第K个结点 PSListNode FindLastKNode(PSListNode pHead, int K) { PSListNode pFast = pHead; PSListNode pSlow = pHead; if (pHead == NULL || K <= 0) { return NULL; } while (--K)//先减判断(倒数第一个节点的话slow,fast同步) { if (pFast == NULL)//没有k个节点 { return NULL; } pFast = pFast->pNext; } while (pFast->pNext)//第一个节点,最后一个节点 { pSlow = pSlow->pNext; pFast = pFast->pNext; } return pSlow; } // 合并两个已序单链表 PSListNode MergeList(PSListNode pL1, PSListNode pL2) { PSListNode pNode = NULL; PSListNode ptailNode = NULL; PSListNode pnewHead = NULL; PSListNode pL1Node = pL1; PSListNode pL2Node = pL2; if (pL1 == NULL) { return pL2; } if (pL2 == NULL) { return pL1; } if (pL1Node->data < pL2Node->data) { pNode = pL1Node; pL1Node = pL1Node->pNext; } else { pNode = pL1Node; pL2Node = pL2Node->pNext; } pnewHead = pNode; ptailNode = pNode; while (pL1Node&&pL2Node) { if (pL1Node->data < pL2Node->data) { pNode = pL1Node; pL1Node = pL1Node->pNext; } else { pNode = pL2Node; pL2Node = pL2Node->pNext; } ptailNode->pNext = pNode; ptailNode = ptailNode->pNext; } if (pL1Node == NULL) { ptailNode->pNext = pL2Node; } else { ptailNode->pNext = pL1Node; } } // 求环的长度,已知在环内相遇节点从相遇节点开始遍历再回到相遇节点就知道环的长度 int GetCyleLen(PSListNode pMeetNode) { int ilen = 1; PSListNode pNode = pMeetNode; if (NULL == pMeetNode) { return 0; } while (pNode->pNext != pMeetNode) { ilen++; } return ilen; } // 单链表排序:冒泡(优化版本) void SortList(PSListNode pHead) { PSListNode ptail = NULL; PSListNode pNode = NULL; PSListNode ppreNode = NULL; if (pHead == NULL||pHead->pNext==NULL) { return; } while (pHead != ptail) { int exchange = 0; ppreNode = pHead; pNode = pHead->pNext; while (pNode != ptail) { if (ppreNode->data > pNode->data) { DataType temp; temp = ppreNode->data; ppreNode->data = pNode->data; pNode->data = temp; exchange = 1; } ppreNode = pNode; pNode = pNode->pNext; } if (exchange == 0)//若第一趟没有交换,有序 { return; } ptail = ppreNode; } } //约瑟夫环问题 PSListNode JosephCircle(PSListNode pHead, int M)//多少人 { PSListNode pNode = pHead; PSListNode pdelete = NULL; int k = M; if (NULL == pHead&&M <= 0) { return; } while (pNode->pNext!=pNode) { k = M; while (--k) { pNode = pNode->pNext; } pdelete = pNode->pNext; pNode->data = pdelete->data; pNode->pNext = pdelete->pNext; free(pdelete); } } // 单链表逆置:两种方法都实现:一、三个指针 二、尾插法 //1.尾插法 void ReverseList(PSListNode* pHead) { assert(NULL != pHead); PSListNode ppreNode = NULL; PSListNode pnewNode = NULL; PSListNode pNode = *pHead; if (*pHead != NULL || (*pHead)->pNext == NULL) { return; } while (pNode) { ppreNode = pNode; pNode = pNode->pNext; ppreNode = pnewNode; pnewNode = ppreNode; } } //2.>三个指针 void ReverseList1(PSListNode* pHead) { if (NULL == *pHead || ((*pHead)->pNext) == NULL); { return; } PSListNode ppreNode = NULL; PSListNode pNode =* pHead; while (pNode != NULL) { PSListNode pNext = pNode->pNext; pNode->pNext = ppreNode; ppreNode = pNode; pNode = pNext; } (*pHead) = ppreNode; } // 求环的入口点 PSListNode FindEnterNode(PSListNode pHead, PSListNode pMeetNode) { PSListNode pNode = pHead; PSListNode pcur = pMeetNode; if (NULL == pHead || NULL == pMeetNode) { return NULL; } while (pNode != pcur) { pNode = pNode ->pNext; pcur = pcur->pNext; } return pNode; } //判断链表是否带环,快慢指针。如带环总会在环内相遇。 PSListNode CheckCycle(PSListNode pHead) { if (NULL == pHead) { return NULL; } PSListNode PSlow = pHead; PSListNode PFast = pHead; while (PFast && PFast->pNext) { PSlow = PSlow->pNext; PFast = PFast->pNext->pNext; if (PSlow == PFast) { return PSlow; } } } int IsListCroseWithCycle(PSListNode pL1, PSListNode pL2) { PSListNode pL1MeetNode = NULL; PSListNode pL2MeetNode = NULL; if (NULL == pL1 || NULL == pL2) { return 0; } pL1MeetNode = CheckCycle(pL1); pL2MeetNode = CheckCycle(pL2); //不带环,遍历2个链表,若尾指针相等,则相交. if (NULL == pL1MeetNode && NULL == pL2MeetNode) { PSListNode pL1Node = pL1; PSListNode pL2Node = pL2; while (pL1Node->pNext != NULL) { pL1Node = pL1Node->pNext; } while (pL2Node->pNext != NULL) { pL2Node = pL2Node->pNext; } if (pL1Node == pL2Node) { return 1; } return 0; } //带环,刚才快慢指针相遇的节点在环内,假如以pL2MeetNode为起点在环内转一圈若可以遇到pL1MeetNode则相交 if (pL1MeetNode != NULL && pL2MeetNode != NULL) { PSListNode pNode = pL2MeetNode; while (pNode->pNext != pL2MeetNode) { if (pNode == pL1MeetNode) { return 1; } pNode = pNode->pNext; } return 0; }