C语言实现无头单链表及链表相关面试题(重点!)

链表通常是面试中的重点,本文是用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;
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值