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

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* LinkListReverse(LinkNode** head) {
    if (head == NULL) {
        return NULL;
    }
    if (*head == NULL || (*head)->next == NULL) {
        return head;
    }
    LinkNode* ptr = NULL;
    LinkNode* cur = *head;
    while (cur != NULL) {
        LinkNode* tmp = cur;
        cur = cur->next;
        tmp->next = ptr;
        ptr = tmp;
    }
    return ptr;
}

12.若带环,求环的长度;求环的入口

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

求环的长度:定义一个指针,从相遇点的下一个节点出发,经过一圈回到相遇点的时候,指针正好走过了一圈,只需要定义一个计数器,得到指针走过的步数即可。
求环的入口点如下图:
《关于链表的一些笔试面试题》

    原文作者:LiuWang_1122
    原文地址: https://blog.csdn.net/yubujian_l/article/details/78916500
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞