C语言实现无头单链表及链表相关面试题(重点!)
来源:互联网 发布:卖淘宝店铺安全吗 编辑:程序博客网 时间:2024/06/07 14:51
链表通常是面试中的重点,本文是用C语言写一个无头单链表,并介绍它的相关面试题的解法。
其中涉及到的面试题如下:
1. 比较顺序表和链表的优缺点,说说它们分别在什么场景下使用?
顺序表:内存中地址连续
长度不可变更
支持随机查找 可以在O(1)内查找元素
适用于需要大量访问元素的 而少量增添/删除元素的程序
链表 :内存中地址非连续
长度可以实时变化
不支持随机查找 查找元素时间复杂度O(n)
适用于需要进行大量增添/删除元素操作 而对访问元素无要求的程序
以下题目会在代码中体现:
2. 从尾到头打印单链表
3. 删除一个无头单链表的非尾节点
4. 在无头单链表的一个非头节点前插入一个节点
5. 单链表实现约瑟夫环
6. 逆置/反转单链表
7. 单链表排序(冒泡排序&快速排序)
8. 合并两个有序链表,合并后依然有序
9. 查找单链表的中间节点,要求只能遍历一次链表
10. 查找单链表的倒数第k个节点,要求只能遍历一次链表
11. 判断单链表是否带环?若带环,求环的长度?求环的入口点。
12. 判断两个链表是否相交,若相交,求交点。(假设链表不带环)
13. 复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表
//list.h#ifndef __LIST_H__#define __LIST_H__#include<stdio.h>#include<stdlib.h>#include<assert.h>typedef int Datetype;typedef struct Node{ Datetype data; struct Node* next;//指向链表的指针,pplist指向链表指针的指针}Node, *pNode, *pList;void InitList(pList* pplist);void DestroyList(pList* pplist);void Insert(pList* pplist, pNode pos, Datetype d);void PushBack(pList* pplist, Datetype d);void PushFront(pList* pplist, Datetype d);void Print(pList plist);void PopBack(pList* pplist);void PopFront(pList* pplist);void Remove(pList* pplist,Datetype d);void RemoveAll(pList* pplist, Datetype d);pNode Find(pList plist,Datetype d);pNode BubbleSort(pList* pplist);void Erease(pList* pplist,pNode pos);void Reverse(pList* pplist);void PrintReverse(pList plist);void DelNottailNode(pNode pos);pNode JosephCycle(pList* pplist, int num);pList Merge(pList l1, pList l2);pList Merge2(pList l1, pList l2);pNode CheckCircle(pList plist);int Circlelength(pNode meet);int CheckCross(pList plist1, pList plist2);pNode GetCircleEntry(pList plist, pNode meet);typedef struct ComplexNode{ Datetype data; struct ComplexNode* next; struct ComplexNode* random;}ComplexNode,*pComplexNode;pComplexNode CreateComplexNode(Datetype d);void PrintComplexNode(pComplexNode head);pComplexNode CloneComplexlist(pComplexNode head);#endif __LIST_H__
再来看各个接口的具体实现:
//list.c#define _CRT_SECURE_NO_WARNINGS 1#include"list.h"//新增节点pNode BuyNode(Datetype d){ pNode NewNode = (pNode)malloc(sizeof(Node)); NewNode->data = d; NewNode->next = NULL; return NewNode;}//链表初始化void InitList(pList* pplist){ assert(pplist); *pplist = NULL;}//后插void PushBack(pList* pplist,Datetype d){ pNode cur = *pplist; pNode newNode = BuyNode(d); assert(pplist); if (cur == NULL) { *pplist = newNode; return; } while (cur->next) { cur = cur->next; } cur->next = newNode;}//打印链表void Print(pList plist){ if (plist == NULL) { return; } pNode cur = plist; while (cur) { printf("%d-->", cur->data); cur = cur->next; } printf("NULL\n");}//销毁void DestroyList(pList* pplist){ pNode cur = *pplist; while (cur) { pNode del = cur; printf("%d\n", del->data); cur = cur->next; free(del); del = NULL; } *pplist = NULL;}//删除void Remove(pList* pplist,Datetype d){ pNode cur = *pplist; pNode prev = NULL; assert(pplist); if (cur == NULL) return; while (cur) { if (cur->data == d) { pNode del = cur; if (cur == *pplist) { //PopFront(pplist); *pplist = cur->next; } else { prev->next = cur->next; } free(del); del = NULL; return; } else { prev = cur; cur = cur->next; } }}//删除所有相同元素void RemoveAll(pList* pplist, Datetype d){ pNode cur = *pplist; pNode prev = NULL; assert(pplist); if (cur == NULL) return; while (cur) { if (cur->data == d) { pNode del = cur; if (cur == *pplist) { //PopFront(pplist); *pplist = cur->next; } else { prev->next = cur->next; } cur = cur->next; free(del); del = NULL; return; } else { prev = cur; cur = cur->next; } }}//后删void PopBack(pList* pplist){ pNode cur = *pplist; assert(pplist); if (cur == NULL) { return; } if (cur->next == NULL) { free(cur); cur = NULL; return; } while (cur->next->next != NULL) { cur = cur->next; } free(cur->next); cur->next = NULL;}//前插void PushFront(pList* pplist, Datetype d){ pNode cur = *pplist; pNode newNode = BuyNode(d); assert(pplist); if (cur == NULL) { *pplist = newNode; } else { newNode->next = cur; *pplist = newNode; }}//后删void PopFront(pList* pplist){ pNode cur = *pplist; assert(pplist); if (cur == NULL) { return; } //一个节点 if (cur->next == NULL) { free(cur); cur = NULL; *pplist = NULL; return; } //两个以上节点 *pplist = cur->next; free(cur); cur = NULL;}//任意位置插入void Insert(pList* pplist, pNode pos, Datetype d){ pNode NewNode = BuyNode(d); pNode cur = pos->next; assert(pplist); assert(pos); if (*pplist == NULL) { PushBack(pplist, d); return; } else { pos->next = NewNode; NewNode->next = cur; }}//查找pNode Find(pList plist, Datetype d){ pNode cur = plist; while (cur) { if (cur->data == d) return cur; cur = cur->next; } return NULL;}//任意位置删除void Erease(pList* pplist,pNode pos){ pNode cur = *pplist; assert(pplist); assert(pos); if (*pplist == NULL) { return; } if (pos->next == NULL)//pos指向尾节点 { PopBack(pplist); return; } else { pNode del = pos->next; pos->data = pos->next->data; pos->next = pos->next->next; free(del); del = NULL; }}//排序pNode BubbleSort(pList* pplist){ pNode cur = *pplist; pNode tail = NULL; assert(pplist); if (*pplist == NULL) { return NULL; } if (cur->next == NULL) { return *pplist; } while (cur != tail) { while (cur->next != tail) { if ((cur->data) > (cur->next->data)) { Datetype tmp = 0; tmp = cur->data; cur->data = cur->next->data; cur->next->data = tmp; } cur = cur->next; } tail = cur; cur = *pplist; } return *pplist;}//逆置无头单链表void Reverse(pList *pplist){ pNode newHead = NULL;//指向第一个节点 pNode cur = *pplist; pNode tmp = NULL; assert(pplist); //没有节点、一个节点 if ((*pplist == NULL) || ((*pplist)->next == NULL)) { return; } /*newHead = *pplist; cur = newHead->next;*/ //newHead->next = NULL; while (cur) { tmp = cur; cur = cur->next; tmp->next = newHead; newHead = tmp; } *pplist = newHead;}//从尾到头打印单链表 递归实现void PrintReverse(pList plist){ pNode cur = plist; if (cur == NULL) { return; } else { PrintReverse(cur->next); printf("%d-->", cur->data); }}//删除一个无头单链表的非尾节点void DelNottailNode(pNode pos){ pNode del = NULL; assert(pos->next); del = pos->next; pos->data = del->data; pos->next = pos->next->next; free(del); del = NULL;}//在无头单链表的非头节点前插入一个节点void InsertFrontNode(pNode pos,Datetype d){ Datetype tmp = 0; pNode newNode = BuyNode(d); newNode->next = pos->next; pos->next = newNode; tmp = pos->data; pos->data = pos->next->data; pos->next->data = tmp;}//单链表实现约瑟夫环pNode JosephCycle(pList* pplist,int num){ pNode cur = *pplist; pNode del = NULL; assert(pplist); while (1) { int count = num; if (cur = cur->next) { break; } while (--count) { cur = cur->next; } printf("%d ", cur->data); del = cur->next; cur->data = cur->next->data; cur->next = cur->next->next; free(cur); cur = NULL; } return cur;}//合并两个有序链表,合并后还是一条有序链表pList Merge(pList l1, pList l2){ pNode cur1 = l1; pNode cur2 = l2; pNode newHead = NULL; pNode tail = NULL; if ((l1 == NULL) && (l2 == NULL)) { return NULL; } if (l1 == NULL)//则l2不为NULL { return l2; } if (l2 == NULL) { return l1; } if (cur1->data <= cur2->data) { newHead = cur1; cur1 = cur1->next; tail = newHead; } else { newHead = cur2; cur2 = cur2->next; tail = newHead; } while (cur1 && cur2) { if (cur1->data < cur2->data) { tail->next = cur1; cur1 = cur1->next; tail = tail->next; } else { tail->next = cur2; cur2 = cur2->next; tail = tail->next; } } if (cur1 == NULL) { tail->next = cur2; } else { tail->next = cur1; } return newHead;}//递归合并pList Merge2(pList l1, pList l2){ pNode cur1 = l1; pNode cur2 = l2; pNode newHead = NULL; pNode tail = NULL; if ((l1 == NULL) && (l2 == NULL)) { return NULL; } if (l1 == NULL)//则l2不为NULL { return l2; } if (l2 == NULL) { return l1; } if (cur1->data <= cur2->data) { newHead = cur1; cur1 = cur1->next; tail = newHead; tail->next = Merge2(cur1, cur2); } else { newHead = cur2; cur2 = cur2->next; tail = newHead; tail->next = Merge2(cur1, cur2); } return newHead;}//查找中间节点的位置,要求只能遍历一次链表pNode FindMidNode(pList plist){ pNode fast = plist; pNode slow = plist; if (plist == NULL) return NULL; while (fast && fast->next) { fast = fast->next->next; slow = slow->next; } return slow;}//查找单链表的倒数第k个节点,要求只能遍历一次链表void DelkNode(pList* pplist, int k){ pNode fast = *pplist; pNode slow = *pplist; pNode del = NULL; assert(pplist); while (fast && fast->next) { fast = fast->next; if (--k <= 0) slow = slow->next; } if (k <= 0) { del = slow->next; slow->data = slow->next->data; slow->next = slow->next->next; free(del); del = NULL; }}//判断链表是否带环pNode CheckCircle(pList plist){ pNode fast = plist; pNode slow = plist; while (fast && fast->next) { fast = fast->next->next; slow = slow->next; if (fast == slow) { return slow; } } return NULL;}//环的长度int Circlelength(pNode meet){ pNode cur = meet; pNode CheckCircle(pList plist); int count = 0; do{ count++; cur = cur->next; } while (cur != meet); return count;}//求环的入口点pNode GetCircleEntry(pList plist, pNode meet){ pNode cur = plist; while (cur != meet) { cur = cur->next; meet = meet->next; } return cur;}//判断两条链表是否相交(不带环)int CheckCross(pList plist1, pList plist2){ if ((plist1 == NULL) || (plist2 == NULL)) { return 0; } while (plist1->next) { plist1 = plist1->next; } while (plist2->next) { plist2 = plist2->next; } return plist1 == plist2;}//复杂链表的打印void PrintComplexNode(pComplexNode head){ pComplexNode cur = head; while (cur) { printf("%d-->", cur->data); printf("random-->[%d]--next-->", cur->random->data); cur = cur->next; } printf("NULL\n");}pComplexNode CreateComplexNode(Datetype d){ pComplexNode newNode = (pComplexNode)malloc(sizeof(ComplexNode)); if (newNode == NULL) { perror("malloc"); return NULL; } newNode->data = d; newNode->next = NULL; newNode->random = NULL; return newNode;}//复杂链表的复制pComplexNode CloneComplexlist(pComplexNode head){ pComplexNode cur = head; pComplexNode tmp = NULL; pComplexNode copy = NULL; pComplexNode tail = NULL; //1.复制每个节点并插入到当前节点的后面 while (cur) { pComplexNode newNode = CreateComplexNode(cur->data); tmp = cur; cur = cur->next; newNode->next = cur; tmp->next = newNode; } //2.调整random指针 cur = head; while (cur) { cur->next->random = cur->random->next; cur = cur->next->next; } //3.分离两条链表 cur = head; copy = cur->next; tail = copy; while (tail->next) { tail->next = tail->next->next; cur->next = tail->next; cur = cur->next; tail = tail->next; } cur->next = NULL; return copy;}
下面是我在写链表过程中的部分测试代码,很遗憾没有写每一个函数的测试用例,这部分还请读者自行上机测试。
//test.c#define _CRT_SECURE_NO_WARNINGS 1#include"list.h"void Test(){ pList plist1 = NULL; pList plist2 = NULL; pNode ret = NULL; InitList(&plist1); InitList(&plist2); PushBack(&plist1, 1); PushBack(&plist1, 2); PushBack(&plist1, 3); PushBack(&plist1, 4); PushBack(&plist1, 5); PushBack(&plist2, 7); PushBack(&plist2, 8); PushBack(&plist2, 9); Find(plist2, 9)->next = Find(plist1, 3); printf("%d\n", CheckCross(plist1, plist2)); //Print(plist1); //ret = CheckCircle(plist1); //if (ret == NULL) //{ // printf("no\n"); //} //else //{ // printf("%d\n", Circlelength(ret)); // //printf("yes\n"); //} /*PushBack(&plist2, 2); PushBack(&plist2, 4); PushBack(&plist2, 6); PushBack(&plist2, 8); PushBack(&plist2, 10); Print(plist2); ret = Merge2(plist1, plist2);*/ //Print(ret); //DestroyList(&ret);}void Test1(){ pComplexNode pNode1 = CreateComplexNode(1); pComplexNode pNode2 = CreateComplexNode(2); pComplexNode pNode3 = CreateComplexNode(3); pComplexNode pNode4 = CreateComplexNode(4); pComplexNode ret = NULL; pNode1->next = pNode2; pNode2->next = pNode3; pNode3->next = pNode4; pNode1->random = pNode4; pNode2->random = pNode1; pNode3->random = pNode2; pNode4->random = pNode2; ret = CloneComplexlist(pNode1); PrintComplexNode(pNode1); PrintComplexNode(ret);}int main(){ Test1(); /*pList plist = NULL; pNode ret = NULL; InitList(&plist); PushBack(&plist, 1); PushBack(&plist, 2); PushBack(&plist, 3); PushBack(&plist, 4);*/ //Find(plist, 4)->next = plist; //ret = JosephCycle(&plist,3); //printf("%d ", ret); //Insert(&plist, Find(plist, 3), 6); /*PushBack(&plist, 5); DelNottailNode(Find(plist, 2)); InsertFrontNode(Find(plist, 3), 6);*/ //Print(plist); //BubbleSort(&plist); //Erease(&plist, Find(plist, 2)); //Erease(&plist, Find(plist, 5)); //Erease(&plist, Find(plist, 4)); //Reverse(&plist); //Print(plist); //PrintReverse(plist); //Remove(&plist, 3); /*PopBack(&plist); Print(plist); PopFront(&plist); ret = Find(plist, 4);*/ //printf("%d ", ret->data); //Print(plist); //void DestroyList(plist); system("pause\n"); return 0;}
- C语言实现无头单链表及链表相关面试题(重点!)
- 单链表相关面试题(C语言实现)
- c语言面试题重点整理·基础类
- c语言面试题重点整理·简单编程类
- c语言面试题重点整理·单链表操作
- 链表常见面试题-C语言实现
- 单链表的实现和相关面试题及其详解(C语言)
- 【数据结构】链表及相关操作(C语言实现)
- 【C语言】单链表相关面试题(一)
- 【C语言】单链表相关面试题(二)
- c语言链表以及面试题
- c语言面试题及答案(转)
- c语言面试题及答案(转)
- C语言面试题及详细解释
- C语言面试题大汇总之华为面试题及部分答案(一)
- java面试题(重点)
- C语言实现单链表-面试题(基础篇)
- 一道多线程面试题-C语言实现
- PAT-A-1057. Stack (30)
- oracle学习笔记(一)
- BZOJ 3211 花神游历各国 线段树
- 170617 numpy数据溢出的对策
- 考研之哈工大
- C语言实现无头单链表及链表相关面试题(重点!)
- webpack安装
- 程序员如何构建知识图谱,让自己更值钱?
- 选项卡
- Android RxJava和Retrofit网络框架封装(一)
- 如何理解CPU卡内部认证与外部认证
- 自动建立用户脚本
- shared_ptr(一)
- python数据分析学习笔记-Numpy-Matplotlib-Pandas