c语言实现单链表面试题
来源:互联网 发布:淘宝新产品推广方案 编辑:程序博客网 时间:2024/06/04 19:58
首先实现一个无头单链表
#include <stdio.h>#include <assert.h>#include <stdlib.h>typedef int DataType;typedef struct ListNode{ DataType data; struct ListNode* next;} ListNode;//打印void PrintList(ListNode* pList){ ListNode* Node = pList; while (Node) { printf(" %d->", Node->data); Node = Node->next; } printf("NULL"); printf("\n");}//尾插void PushBack(ListNode** ppList, DataType x){ if (*ppList == NULL) { ListNode* Node = (ListNode*)malloc(sizeof(ListNode)); Node->data = x; Node->next = NULL; *ppList = Node; } //只有一个节点 else if ((*ppList)->next == NULL) { (*ppList)->next = (ListNode*)malloc(sizeof(ListNode)); (*ppList)->next->data = x; (*ppList)->next->next = NULL; } //多个节点 else { ListNode* Node = *ppList; while (Node->next) { Node = Node->next; } Node->next = (ListNode*)malloc(sizeof(ListNode)); Node->next->data = x; Node->next->next = NULL; }}//尾删void PopBack(ListNode** ppList){ if (*ppList == NULL) return; //只有一个节点,直接释放 else if ((*ppList)->next == NULL) { free(*ppList); *ppList = NULL; } else { ListNode* Node = *ppList; while (Node->next) { Node = Node->next; } free(Node); Node = NULL; }}//头插void PushFront(ListNode** ppList, DataType x){ if (*ppList == NULL) { ListNode* Node = (ListNode*)malloc(sizeof(ListNode)); Node->data = x; *ppList = Node; (*ppList)->next = NULL; } else { ListNode* Node = (ListNode*)malloc(sizeof(ListNode)); Node->data = x; Node->next = *ppList; *ppList = Node; }}//头删void PopFront(ListNode** ppList){ if (*ppList == NULL) return; else if ((*ppList)->next == NULL) { free(*ppList); *ppList = NULL; } else { //保存指针的指向 ListNode* tmp = (*ppList)->next; free(*ppList); *ppList = tmp; }}//查找ListNode* Find(ListNode* pList, DataType x){ assert(pList); while (pList) { if (pList->data == x) { return pList; } pList = pList->next; } return NULL;}//在pos的前面插入一个节点void Insert(ListNode** ppList, ListNode* pos, DataType x){ assert(*ppList); assert(pos); if ((*ppList)->next == NULL || pos == *ppList) { PushFront(ppList, x); } else { ListNode* tmp = NULL; ListNode* head = *ppList; while (head->next != pos) { head = head->next; } tmp =(ListNode*) malloc(sizeof(ListNode)); tmp->data = x; head->next = tmp; tmp->next = pos; }}//删除一个节点void Erase(ListNode** ppList, ListNode* pos){ assert(*ppList && pos); if ((*ppList)->next == NULL || pos == *ppList) { PopFront(ppList); } else { ListNode* tmp = *ppList; while (tmp->next != pos) { tmp = tmp->next; } tmp->next = pos->next; free(pos); pos = NULL; }}
1.比较顺序表和链表的优缺点,说说它们分别在什么场景下使用?
空间上的比较(Space)
- 空间的开辟:
顺序表的实现一般是实现连续开辟一段空间(或根据需求动态连续开辟空间),然后在进行数据的增删查改(静态顺序表),所以顺序表一般是固定空间大小的;
单链表则是一次只开辟一个结点的空间,用来存储当前要保存的数据及指向下一个结点或NULL的指针,所以单链表的空间大小是动态变化的。
- 空间的使用:
当我们不知道要存储多少数据时,用顺序表来开辟的空间如果太大,就会造成一定程度上的浪费。
用单链表实现时,因为是每需要存储一个数据时,才开辟一个空间,虽然有非数据项的指针占空间,但相比顺序表来说,浪费不是那么明显。(因为链表每次都是开辟的位置都是随机的,那么可能会把这块空间搞得七零八碎,出现很多小的一般使用不到的碎片空间)
- 对CPU高速缓存的影响:
顺序表的空间一般是连续开辟的,而且一次会开辟存储多个元素的空间,所以在使用顺序表时,可以一次把多个数据写入高速缓存,再写入主存,顺序表的CPU高速缓存效率更高,且CPU流水线也不会总是被打断;
单链表是每需要存储一个数据才开辟一次空间,所以每个数据存储时都要单独的写入高速缓存区,再写入主存,这样就造成了,单链表CPU高速缓存效率低,且CPU流水线会经常被打断。
时间上的比较(Time)
查找随机元素的时间复杂度:
顺序表访问随机元素的时间复杂度是O(1),而单链表访问随机元素的时间复杂度是O(n)。随机位置插入、删除元素的时间复杂度:
顺序表在插入随机位置插入、删除元素的平均时间复杂度是O(n),
单链表在插入随机位置插入、删除元素的时间复杂度是O(1)。
应用场景:
根据时间复杂度比较:
在查询操作使用的比较频繁时,使用顺序表会好一些;
在插入、删除操作使用的比较频繁时,使用单链表会好一些。
2.从尾到头打印单链表
void PrintHeadtoTail(ListNode* pList){ if (pList == NULL) { printf("NULL\n"); return; } while (pList) { printf(" %d->", pList->data); pList = pList->next; } printf("NULL\n");}//递归方式void PrintHeadtoTail(ListNode* pList){ if (pList == NULL) { printf("NULL"); return; } printf("%d->", pList->data); PrintHeadtoTail(pList->next);}
3.删除一个无头单链表的非尾节点
无头单链表无法找到pos的前一个节点,只能把pos后一个节点的内容赋值给pos然后删掉pos后一个节点
void EraseNoTail(ListNode* pos){ if ((pos == NULL) && (pos->next == NULL)) { return; } else { ListNode *next = pos->next; pos->next = next->next; pos->data = next->data; free(next); next = NULL; }}
4.在无头单链表的一个节点前插入一个节点
先申请一个节点插入到pos后面,然后再与pos的内容相交换
void FrontInsert(ListNode* pos,DataType x){ assert(pos); ListNode *tmp = (ListNode*)malloc(sizeof(ListNode)); tmp->next = pos->next; pos->next = tmp; tmp->data = pos->data; pos->data = x;}
5.单链表实现约瑟夫环
ListNode* JosephRing(ListNode *pList, DataType k){ assert(pList); int count = 0; ListNode* tmp = NULL; while (pList != pList->next) { count = k; while (--count) { pList = pList->next; } pList->data = pList->next->data; tmp = pList->next; pList->next = pList->next->next; free(tmp); tmp = NULL; } return pList;}
6.逆置/反转单链表
ListNode* Reverse(ListNode* plist)//逆置反转单链表{ ListNode* newhead = NULL; ListNode* pos = list; ListNode* cur = pos; while (cur) { pos = cur; cur = cur->next; pos->next = newhead; newhead = pos; } return newhead;}
7.单链表排序(冒泡排序&快速排序)
ListNode *Bubblesort(ListNode *plist)//单链表排序(冒泡排序&快速排序){ if ((plist == NULL) || (plist->next == NULL)) { } else { ListNode *cur = NULL; ListNode *next = NULL; ListNode *tail = NULL; while (tail != plist->next) { cur = plist; next = plist->next; while (next != tail) { if (cur->data > next->data) { DataType tmp = next->data; next->data = cur->data; cur->data = tmp; } cur = next; next = next->next; } tail = cur; } cur = next = tail = NULL; } return plist;}
8.合并两个有序链表,合并后依然有序
ListNode *Merge(ListNode *plist1,ListNode *plist2){ ListNode *tail = NULL; ListNode *tmp = NULL; ListNode *plist = NULL; if (plist1 == NULL) { return plist2; } if (plist2 == NULL) { return plist1; } while (plist1 && plist2) { if (plist1->data < plist2->data) { tmp = plist1; plist1 = plist1->next; } else { tmp = plist2; plist2 = plist2->next; } if (plist == NULL) { plist = tmp; tail =ist; } else { tail->next = tmp; tail = tmp; } } if (plist1 == NULL) { tail->next = plist2; } else { tail->next = plist1; } return plist; }
9.查找单链表的中间节点,要求只能遍历一次链表
ListNode *FindMidNode(ListNode *plist){ assert(plist); ListNode *fast = plist; ListNode *slow = plist; while (fast && fast->next) { fast = fast->next->next; slow = slow->next; } return slow;}
10.查找单链表的倒数第k个节点,要求只能遍历一次链表
ListNode *FindTailKNode(ListNode *plist,int k){ ListNode *fast = plist; ListNode *slow = plist; assert(plist); while (--k) { fast = fast->next; assert(fast); } while (fast->next != NULL) { fast = fast->next; slow = slow->next; } return slow;}
- c语言实现单链表面试题
- C语言实现单链表面试题汇总
- C语言实现单链表面试题--基础篇
- C语言实现单链表面试题--基础篇
- C语言实现单链表面试题--进阶
- C语言实现单链表面试题(基础篇)
- C语言实现单链表面试题(进阶篇)
- C语言实现单链表面试题--进阶
- C语言实现单链表面试题--基础篇
- c语言实现单链表面试题--基础篇
- c语言实现单链表面试题——进阶
- C语言实现单链表面试题汇总
- C语言实现单链表面试题_基础篇
- C语言实现单链表面试题(基础篇)
- C语言实现单链表面试题---基础篇
- c语言实现单链表面试题(基础篇)
- C语言实现单链表面试题 ----基础篇
- c语言实现单链表面试题之进阶篇
- 【旧资料整理】gcc获取一个动态库的调用流程
- 【旧资料整理】主屏幕应用程序意外停止解决办法
- 1050. String Subtraction 字符串相减
- 【旧资料整理】libnids 隐性BUG
- java学习 jstl多条件判断
- c语言实现单链表面试题
- 总结3-EL表达式
- react/vue两种实现星级评分效果
- 【旧资料整理】亲测有效的转载汇总
- 打造自己linux的bashrc
- http://127.0.0.1:8000/ 拒绝了我们的连接请求。
- 无线网络覆盖
- ubuntu进程管理方法
- 图的收缩