您的位置:首页 > 职场人生

关于链表的一些笔试面试题

2017-12-27 21:11 281 查看
1.逆序打印单链表(递归)

#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;
}


求环的长度:定义一个指针,从相遇点的下一个节点出发,经过一圈回到相遇点的时候,指针正好走过了一圈,只需要定义一个计数器,得到指针走过的步数即可。

求环的入口点如下图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  面试题 单链表