关于链表的一些笔试面试题
2017-12-27 21:11
281 查看
1.逆序打印单链表(递归)
2.删除一个无头结点的单链表的非尾节点(不能遍历链表)
这里运用的方法就是将要删除的节点的下一个节点的内容放到pos中,将pos->next 删除,从而删除了我们想要删除的内容。
3.在无头单链表的一个节点前插入一个节点(不能遍历链表)
4.单链表实现约瑟夫环(JosephCircle)
5.单链表的冒泡排序
6.合并两个有序链表,合并后依然有序
7.查找单链表的中间节点,要求只能遍历一遍链表
利用快慢指针,快指针每次走一步,慢指针每次走两步,当快指针指向了链表末尾时,慢指针正好指向了链表的中间节点。
8.查找单链表的倒数第k个节点,要求只能遍历一次链表
本题的思路与上一题的相似,先让一个指针走k步,再让另一个指针出发,两个指针的速度都是每次走一步,这样到先走的指针到达链表末尾时,后走的指针正好走到了倒数第k个节点处。
9.删除链表的倒数第k个节点
10.判断链表是否带环
快慢指针,快指针每次走两步,慢指针每次走一步,如果两个指针相遇,说明链表一定带环。
11.若带环,求环的长度;求环的入口
求环的长度:定义一个指针,从相遇点的下一个节点出发,经过一圈回到相遇点的时候,指针正好走过了一圈,只需要定义一个计数器,得到指针走过的步数即可。
求环的入口点如下图:
#include<stddef.h> #include<stdio.h> #include<windows.h> typedef char LinkType; typedef struct LinkNode{ LinkType data; struct LinkNode* next; }LinkNode; void LinkListReversePrint(LinkNode* head) { if (head == NULL) { //空链表 return; } if (head->next != NULL) { LinkListReversePrint(head->next); } printf("%c ", head->data); }
2.删除一个无头结点的单链表的非尾节点(不能遍历链表)
void LinkListErase(LinkNode** head, LinkNode* pos) { if (head == NULL || pos == NULL) { //非法输入 return; } if (*head == NULL) { //空链表 return; } if (pos->next == NULL) { return; } LinkNode* to_delete = pos->next; pos->data = to_delete->data; pos->next = to_delete->next; LinkListDestroyNode(to_delete);//销毁节点,防止内存泄漏 return; }
这里运用的方法就是将要删除的节点的下一个节点的内容放到pos中,将pos->next 删除,从而删除了我们想要删除的内容。
3.在无头单链表的一个节点前插入一个节点(不能遍历链表)
void LinkListInsertBefore(LinkNode** head, LinkNode* pos, LinkType value) { if (head == NULL) { //非法输入 return; } if (*head == NULL) { //空链表 *head = LinkListCreateNode(value); return; } if (*head == pos) { LinkNode* new_node = LinkListCreateNode(value); new_node->next = pos; *head = new_node; return; } LinkNode* cur = *head; while (cur->next != pos && cur->next != NULL) { cur = cur->next; } LinkNode* new_node = LinkListCreateNode(value); cur->next = new_node; new_node->next = pos; return; }
4.单链表实现约瑟夫环(JosephCircle)
LinkNode* JosephCircle(LinkNode* head, size_t n) { if (head == NULL) { return; } LinkNode* cur = head; while(cur->next != cur){ size_t i = 1; for (; i < n; i++) { cur = cur->next; } LinkNode* to_delete = cur->next; cur->data = to_delete->data; cur->next = to_delete->next; LinkListDestroyNode(to_delete); } return cur; }
5.单链表的冒泡排序
void LinkListBubbleSort(LinkNode* head) { if (head == NULL) { return; } LinkNode* cur = head; while (cur != NULL) { LinkNode* ptr = head; while (ptr != cur) { if (ptr->data > ptr->next->data) { LinkType tmp = ptr->data; ptr->data = ptr->next->data; ptr->next->data = tmp; } ptr = ptr->next; } cur = cur->next; } }
6.合并两个有序链表,合并后依然有序
LinkNode* LinkListMerge(LinkNode* head1, LinkNode* head2) { if (head1 == NULL) { return head2; } if (head2 == NULL) { return head1; } LinkNode* head = NULL; LinkNode* cur1 = head1; LinkNode* cur2 = head2; if (cur1->data > cur2->data) { head = cur2; cur2 = cur2->next; } else if(cur1->data < cur2->data) { head = cur1; cur1 = cur1->next; } else { head = cur1; cur1 = cur1->next; cur2 = cur2->next; } LinkNode* cur = head; while (cur1 != NULL && cur2 != NULL) { if (cur1->data > cur2->data) { cur->next = cur2; cur2 = cur2->next; } else if(cur1->data < cur2->data){ cur->next = cur1; cur1 = cur1->next; } else { cur->next = cur1; cur1 = cur1->next; cur2 = cur2->next; } cur = cur->next; } if (cur1 != NULL) { //当head2的长度小于head1时,将head1剩下的内容放到head中 cur->next = cur1; } if (cur2 != NULL) { //当head1的长度小于head2时,将head2剩下的内容放到head中 cur->next = cur2; } return head; }
7.查找单链表的中间节点,要求只能遍历一遍链表
LinkNode* FindMidNode(LinkNode* head) { if (head == NULL) { return; } LinkNode* fast = head; LinkNode* slow = head; while (fast != NULL && fast->next != NULL) { slow = slow->next; fast = fast->next->next; } return slow; }
利用快慢指针,快指针每次走一步,慢指针每次走两步,当快指针指向了链表末尾时,慢指针正好指向了链表的中间节点。
8.查找单链表的倒数第k个节点,要求只能遍历一次链表
LinkNode* FindLastKNode(LinkNode* head, size_t K) { if (head == NULL) { return; } size_t size = LinkListSize(head); if (K == NULL || K > size) { return; } LinkNode* fast = head; LinkNode* slow = head; while (--K) { fast = fast->next; } while (fast != NULL && fast->next != NULL) { fast = fast->next; slow = slow->next; } return slow; }
本题的思路与上一题的相似,先让一个指针走k步,再让另一个指针出发,两个指针的速度都是每次走一步,这样到先走的指针到达链表末尾时,后走的指针正好走到了倒数第k个节点处。
9.删除链表的倒数第k个节点
void EraseLastKNode(LinkNode** head, size_t K) { if (head == NULL) { return; } if (*head == NULL) { return; } if (K == 1) { LinkListPopBack(head);//头删 } else { LinkNode* ptr = FindLastKNode(*head, K); LinkNode* to_delete = ptr->next; ptr->data = to_delete->data; ptr->next = to_delete->next; LinkListDestroyNode(to_delete); } }
10.判断链表是否带环
int HasCycle(LinkNode* head) { LinkNode* fast = head; LinkNode* slow = head; while (fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; if (fast == slow) { return 1; } } return 0; }
快慢指针,快指针每次走两步,慢指针每次走一步,如果两个指针相遇,说明链表一定带环。
11.若带环,求环的长度;求环的入口
LinkNode* HasCycle(LinkNode* head) { LinkNode* fast = head; LinkNode* slow = head; while (fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; if (fast == slow) { return slow; } } return 0; } size_t GetCycleLen(LinkNode* head) { LinkNode* fast = head; LinkNode* slow = head; while (fast != NULL && fast->next != NULL) { fast = fast->next->next; slow = slow->next; if (slow == fast) { LinkNode* cur = slow->next; size_t len = 1; while (cur != slow) { cur = cur->next; len++; } return len; } } return NULL; } LinkNode* GetCycleEntry(LinkNode* head) { LinkNode* ret = HasCycle(head); LinkNode* cur = head; if (ret == NULL) { //不带环 return NULL; } while (cur != ret) { cur = cur->next; ret = ret->next; } return ret; }
求环的长度:定义一个指针,从相遇点的下一个节点出发,经过一圈回到相遇点的时候,指针正好走过了一圈,只需要定义一个计数器,得到指针走过的步数即可。
求环的入口点如下图:
相关文章推荐
- 关于链表的一些经典问题以及相关面试题
- 数据结构学习笔记 --- 线性表 (一些常见的关于链表的算法和面试题)
- 面试收集--关于链表的一些面试题
- 关于链表面试题的一些理解
- 关于链表的一些面试题
- 关于链表笔试题的一些收集
- 数据结构学习笔记 --- 线性表 (一些常见的关于链表的算法和面试题)
- 关于链表的,有一些错误老是解决不了,大家帮忙看看
- 关于数据库(Mysql)的一些面试(笔试)问题
- 关于sizeof的笔试面试题具体解释
- Java 关于线程的一些面试题
- 关于数据结构中单链表一些操作
- C++笔试题(剑指offer 面试题5 将单向链表数据,逆向打印输出)
- 找链表的中间结点和倒数第k个结点(链表笔试题面试题)
- 曾经遇到的一个面试题,快速排序用链表实现,算法和以前的相似,需要注意一些细节处理
- 关于链表的一些问题
- 一些关于树的面试题
- 记一道关于链表的面试题
- 链表笔试面试题
- 关于多线程的笔试面试题