单链表的实现和相关面试题及其详解(C语言)

来源:互联网 发布:android端编程软件 编辑:程序博客网 时间:2024/06/08 01:15

 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的链接次序实现的

链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。

每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。


链表的具体实现:

头文件及函数声明(LinkNode.h)部分

#ifndef __LINKLIST_H__ #define __LINKLIST_H__ #include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>typedef int DataType; typedef struct Node { DataType data; struct Node* next; }Node, *pNode, *pList;void InitLinkList(pList* pplist); //初始化void PushFront(pList*pplist, DataType x);//前加void PopFront(pList *pplist);//前删void Display(pList pl); //打印void DestroyList(pList* pplist);//销毁 void PushBack(pList*pplist, DataType x);//后加pNode Find(pList pl, DataType x); //查找函数void Remove(pList *pplist, DataType x);//删除指定数据所在节点//常见面试题void Show(pList pl); //逆序打印void DelNotTail(pNode pos); //删除无头链表的非尾节点void InsertFrontNode(pNode pos, DataType x); //当前节点插入一个数据void JosephCycle(pList pl, int k); //约瑟夫环void ReverseList(pList* pplist); //逆序链表void BubbleSortList(pList plist); //冒泡排序链表pList Merge(pList* ppl1, pList* ppl2); //合并两个有序链表pNode FindMidNode(pList plist); //查找链表的中间节点void DelKNode(pList plist, int k);//删除倒数第k个节点pNode CheckCycle(pList plist);//判断是否有环int GetCircleLength(pNode meet);//求环的长度pNode GetCircleEntryNode(pNode meet, pList plist);//求环的入口pNode CheckCross(pList p1, pList p2);//判断是否相交,若相交,求交点#endif //__LINKLIST_H__
各个函数的实现(LinkNode.c)部分
#include "LinkNode.h"void InitLinkList(pList* pplist)//初始化{assert(pplist != NULL);*pplist = NULL;}void PushFront(pList*pplist, DataType x)//前加{assert(pplist != NULL);pNode node = malloc(sizeof(Node));if (node == NULL){perror("malloc");exit(EXIT_FAILURE);}node->data = x;node->next = NULL;node->next = *pplist;*pplist = node;}void PopFront(pList *pplist)//前删{assert(pplist != NULL);pNode head = *pplist;if (head == NULL){return;}*pplist = head->next;free(head);head -> next = NULL;}void Display(pList pl)//打印{if (pl == NULL){return;}while (pl != NULL){printf("%d-->", pl->data);pl = pl->next;}printf("\n");}void DestroyList(pList* pplist)//销毁 {assert(pplist != NULL);while (*pplist != NULL){pNode tmp = (*pplist)->next;free(*pplist);(*pplist)->next = NULL;*pplist = tmp;}}void PushBack(pList*pplist, DataType x)//后加{assert(pplist != NULL);pNode head = *pplist;pNode cur = NULL;pNode new = malloc(sizeof(Node));if (new == NULL){perror("malloc");exit(EXIT_FAILURE);}else if (head == NULL){*pplist = new;new->data = x;new->next = NULL;}else{while (head!=NULL){cur = head;head = head->next;}cur->next = new;new->data = x;new->next = NULL;}}pNode Find(pList pl, DataType x) //查找函数{pNode head = pl;while (head->data != x){head = head->next;}if (head->data == x){return head;}else{return NULL;}}void Remove(pList *pplist, DataType x)//删除指定数据所在节点{assert(pplist != NULL);pNode del = NULL;pNode cur = Find(*pplist,x);if (cur == NULL){return;}del = cur->next;cur->data = del->data;cur->next = del->next;free(del);del->next = NULL;}//常见面试题//逆序打印(递归实现)void Show(pList pl) {if (pl == NULL){return;}else if (pl != NULL){Show(pl->next);printf("%d-->", pl->data);}}//删除无头链表的非尾节点//因为无头,所以做不到直接把该节点删除,所以将本要删除的那个节点的//下一个节点的数据和指针拷贝到该节点,然后将下一个节点删掉。void DelNotTail(pNode pos){assert(pos != NULL);pNode del = NULL;del = pos->next;pos->data = del->data;pos->next = del->next;free(del);del->next = NULL;}void InsertFrontNode(pNode pos, DataType x) //当前节点插入一个数据{pNode new = malloc(sizeof(Node));if (new == NULL){perror("malloc");exit(EXIT_FAILURE);}new->data = pos->data;pos->data = x;new->next = pos->next;pos->next = new;}//约瑟夫环//每数到三就将第三个节点删除,然后从下一个节点开始数void JosephCycle(pList pl, int k) {pNode cur = pl;pNode del = pl;while (1){if (cur->next == cur)//如果只有一个节点了,就停下来{printf("%d \n", cur->data);break;}int count = k;pNode tmp = NULL;while (--count > 0)//相当于数数过程,while循环停下就该删停的那个节点了{cur = del;del = del->next;}cur->next = del->next;//cur往前走一步,致使下次数数从删除的下一个节点开始printf("%d  ", del->data);tmp = del;del = del->next;free(tmp);tmp->next = NULL;}}//逆序链表void ReverseList(pList* pplist) {assert(pplist != NULL);if ((*pplist == NULL)||((*pplist)->next==NULL)){return;}else{pNode pre = *pplist;pNode cur = (*pplist)->next;pNode tail = (*pplist)->next->next;pNode tmp = NULL;while (1){cur->next = pre;pre->next = tmp;tmp = pre;if (tail == NULL){break;}else{pre = cur;cur = tail;tail = tail->next;}}*pplist = cur;}}    void BubbleSortList(pList plist) //冒泡排序链表{pNode cur = plist;pNode tail = NULL;if ((plist == NULL) || ((plist)->next == NULL)){return;}while (tail != plist){while (cur->next!=tail){if (cur->data > cur->next->data){DataType tmp = cur->data;cur->data = cur->next->data;cur->next->data = tmp;cur = cur->next;}}if (cur->next == tail){tail = cur;cur = plist;}}}pList Merge(pList* ppl1, pList* ppl2) //合并两个有序链表{pNode head = NULL;pNode cur = NULL;assert(ppl1 != NULL);assert(ppl2 != NULL);if ((*ppl1)->data < (*ppl2)->data){head = *ppl1;cur = head;*ppl1 = (*ppl1)->next;}else{head = *ppl2;cur = head;*ppl2 = (*ppl2)->next;}while ((*ppl1 != NULL) && (*ppl2 != NULL)){if ((*ppl1)->data < (*ppl2)->data){cur->next = *ppl1;*ppl1 = (*ppl1)->next;}else{cur->next = *ppl2;*ppl2 = (*ppl2)->next;}cur = cur->next;}if (*ppl1 != NULL){cur->next = *ppl1;}else if (*ppl2 != NULL){cur->next = *ppl2;}return head;}//查找链表的中间节点//创建两个指针,一个指针每次走两步(快),一个指针每次走一步(慢),//当快的走完了,则慢的刚好走到一半,慢指针的位置就是中点pNode FindMidNode(pList plist) {pNode fast = plist;pNode slow = plist;if (plist == NULL){return NULL;}while ((fast != NULL) && (fast->next!=NULL)){fast = fast->next->next;slow = slow->next;}return slow;}//删除倒数第k个节点//创建两个指针,一个先走k-1步,另一个再开始走,先走的走到终点了,后走的刚好走到了倒数第k个节点void DelKNode(pList plist, int k){pNode first = plist;pNode second = plist;pNode del = NULL;if (plist == NULL|| 0==k){return ;}while ((first != NULL) && (first->next != NULL)){while (--k>0){del = first;first = first->next;}first = first->next;second = second->next;}del = second->next;second->data = del->data;second->next = del->next;free(del);del->next = NULL;}//判断是否有环//创建两个指针,一个指针每次走两步(快),一个指针每次走一步(慢)//如果有环,走着走着,快慢指针会相遇,循环停下来提前将快指针返回,此时快指针一定不为NULL//如果没有环,那么快指针就会先走到终点,然后循环停下来,返回NULLpNode CheckCycle(pList plist){pNode fast = plist;pNode slow = plist;if (plist == NULL){return NULL;}while ((fast != NULL) && (fast->next != NULL)) {fast = fast->next->next;slow = slow->next;if (fast == slow){return fast;}}return NULL;}//求环的长度//用一个meet指针将相遇点记住,然后让Meet指针从相遇点出发,走一步记一步,//当Meet指针回到相遇点及Meet=meet时刚好走了一圈,长度也就求出来了int GetCircleLength(pNode meet){pNode Meet = NULL;int count = 0;if (meet == NULL){return count;}Meet = CheckCycle(meet);meet = Meet;Meet = Meet->next;count++;while (Meet != meet){count++;Meet = Meet->next;}return count;}//求环的入口//这个后边会有一篇博客专门讲到这个,在此就不多做解释了pNode GetCircleEntryNode(pNode meet, pList plist){pNode first = meet;pNode second = plist;if ((plist == NULL) || (meet==NULL)){return NULL;}while (first!=second){first = first->next;second = second->next;}return first;}//判断是否相交,若相交,求交点//将一条链的尾部连到另一条链的第一个节点,//就将此问题转换成了判断是否环换问题//如果有交点,则会形成环,无则就是一条普通的链pNode CheckCross(pList p1, pList p2){pNode cur1 = p1;pNode meet = NULL;pNode ret = NULL;while (cur1->next != NULL){cur1 = cur1->next;}cur1->next = p2;meet = CheckCycle(p1);//meet表示交点,交点为空即为没有交点if (meet == NULL){return NULL;}ret = GetCircleEntryNode(meet, p1);return ret;}
测试函数(test.c)部分
#include "LinkNode.h"void test1(){pList list;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);Display(list);PopFront(&list);Display(list);PopFront(&list);Display(list);PopFront(&list);Display(list);PopFront(&list);Display(list);DestroyList(&list);}void test2(){pList list;InitLinkList(&list);PushBack(&list, 1);PushBack(&list, 2);PushBack(&list, 3);PushBack(&list, 4);Display(list);pNode ret = Find(list, 3);printf("%d\n", ret->data);DestroyList(&list);}void test3(){pList list;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);Display(list);Remove(&list,3);Display(list);DestroyList(&list);}void test4(){pList list;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);Display(list);Show(list);DestroyList(&list);}void test5(){pList list;pNode ret = NULL;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);Display(list);ret = Find(list, 3);DelNotTail(ret);Display(list);DestroyList(&list);}void test6(){pList list;pNode ret = NULL;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);Display(list);ret = Find(list, 3);InsertFrontNode(ret,5); Display(list);DestroyList(&list);}void test7(){int i = 0;pList list;InitLinkList(&list);for (i = 41; i >= 1; i--){PushFront(&list, i);}Find(list, 41)->next = list;JosephCycle(list, 3);}void test8(){pList list;pNode ret = NULL;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);Display(list);ReverseList(&list);Display(list);DestroyList(&list);}void test9(){pList list;pNode ret = NULL;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);Display(list);BubbleSortList(list);Display(list);DestroyList(&list);}void test10(){pList list1;pList list2;pList new = NULL;InitLinkList(&list1);PushFront(&list1, 7);PushFront(&list1, 5);PushFront(&list1, 3);PushFront(&list1, 1);InitLinkList(&list2);PushFront(&list2, 8);PushFront(&list2, 6);PushFront(&list2, 4);PushFront(&list2, 2);Display(list1);Display(list2);new = Merge(&list1, &list2);Display(new);DestroyList(&new);}void test11(){pList list;pNode ret = NULL;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);PushFront(&list, 5);PushFront(&list, 6);PushFront(&list, 7);PushFront(&list, 8);PushFront(&list, 9);Display(list);ret = FindMidNode(list);printf("%d\n", ret->data);DestroyList(&list);}void test12(){pList list;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);PushFront(&list, 5);PushFront(&list, 6);PushFront(&list, 7);PushFront(&list, 8);PushFront(&list, 9);Display(list);DelKNode(list, 3);Display(list);DestroyList(&list);}void test13(){pList list;pNode ret = NULL;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);PushFront(&list, 5);PushFront(&list, 6);PushFront(&list, 7);PushFront(&list, 8);PushFront(&list, 9);Find(list, 1)->next = Find(list, 5);ret = CheckCycle(list);if (ret == NULL){printf("NO\n");}else{printf("YES\n");}}void test14(){pList list;int ret = 0;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);PushFront(&list, 5);PushFront(&list, 6);PushFront(&list, 7);PushFront(&list, 8);PushFront(&list, 9);Find(list, 1)->next = Find(list, 5);ret = GetCircleLength(list);printf("length=%d\n", ret);}void test15(){pList list;pNode ret = NULL;pNode meet = NULL;InitLinkList(&list);PushFront(&list, 1);PushFront(&list, 2);PushFront(&list, 3);PushFront(&list, 4);PushFront(&list, 5);PushFront(&list, 6);PushFront(&list, 7);PushFront(&list, 8);PushFront(&list, 9);Find(list, 1)->next = Find(list, 5);meet = CheckCycle(list);ret = GetCircleEntryNode(meet,list);if (ret == NULL){printf("NOCYCLE\n");}else{printf("the entry is:%d\n",ret->data);}}void test16(){pList list1;pList list2;pList ret = NULL;InitLinkList(&list1);InitLinkList(&list2);PushFront(&list1, 11);PushFront(&list1, 10);PushFront(&list1, 9);PushFront(&list1, 7);PushFront(&list1, 5);PushFront(&list1, 3);PushFront(&list1, 1);PushFront(&list2, 8);PushFront(&list2, 6);PushFront(&list2, 4);PushFront(&list2, 2);Find(list2, 8)->next = Find(list1, 10);Display(list1);Display(list2);ret = CheckCross(list1, list2);if (ret == NULL){printf("NOCROSS\n");}else{printf("the point of intersection is:%d\n", ret->data);}}int main(){//test1();//前插和前删//test2();//后插和查找//test3();//指定删除//test4();//逆序打印//test5();//删除非尾节点//test6();//当前节点插入一个数据//test7();//约瑟夫环  (打印的是依次删除的顺序)//test8();//逆置单链表//test9();//冒泡排序(从小到大)//test10();//合并有序链表//test11();//找中间节点//test12();//删除倒数第k个元素//test13();//判断是否有环//test14();//求环的长度//test15();//求环的入口//test16();//判断是否相交,若相交求交点return 0;}
PS:测试函数部分,想要测试那个函数的功能将其放开就OK了

阅读全文
0 0
原创粉丝点击