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

来源:互联网 发布:卖淘宝店铺安全吗 编辑:程序博客网 时间:2024/06/07 14:51

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