单链表面试题(一)

链表是最基本的数据结构,链表的相关操作也比较简单,同时它也包含了指针的运用,能把许多知识结合起来,因此链表的面试题在面试中占据很重要的地位,所以我整理了一些关于链表的面试题与大家分享。

下图是其中一道求带环链表入口点题的分析图
求带环链表环的入口点

//.h
#ifndef __LIST_H__
#define __LIST_H__
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
typedef  int   Datatype;
typedef struct Node
{
    Datatype data;
    struct Node*next;
}Node, *pNode, *pList;
//打印链表信息
void display(pList plist);
//销毁链表
void Destroylist(pList*pplist);
//查找某个元素
pNode find(pList plist, Datatype x);
//头部插入数据
void pushfront(pList*pplist, Datatype x);
//逆序打印链表内容
void Invert_display(pList pplist);
//链表的逆序
void Invert_list(pList*pplist);
//链表的合并
pList Merge(pList*ls1, pList*ls2);
//链表的合并递归版本
pList _Merge(pList*ls1, pList*ls2);
//删除一个非尾节点
void DelNotTail(pNode pos);
//在一个位置前插入一个节点
void InsertFrontNode(pNode pos, Datatype x);
//约瑟夫环
void JosephCycle(pList plist, int k);
//寻找一个链表的中间节点,只能遍历一次
pNode FindMidNode(pList plist);
//对链表的冒泡排序
void Bubblesort(pList plist);
//删除倒数第k个元素
void DelKNode(pList *plist, int k);
//判断一个单链表是否有环
pNode CheckCycle(pList plist);
//求一个带环单链表环的长度
int GetCircleLength(pNode meet);
//法一:求一个带环单链表环的入口点
pNode GetCircleEntreNode(pNode meet, pList plist);
//法二:求一个带环单链表环的入口点
pNode _GetCircleEntreNode2 (pList plist,int Length);
//判断两个不带环单链表是否相交
pNode  CheckCross(pList plist1, pList plist2);
//求两个相交不带环单链表的交点
pNode GetCrossNode(pList plist1, pList plist2);
#endif //__LIST_H__
//.c
#include"list.h"
//打印
void display(pList plist)
{
    pNode head = plist;
    while (head != NULL)
    {
        printf("%d-->", head->data);
        head = head->next;
    }
    printf("over\n");
}
//查找特定元素
pNode find(pList plist, Datatype x)
{
    pNode head = plist;
    while (plist != NULL)
    {
        if (plist->data == x)
            return plist;
        plist = plist->next;
    }
    return NULL;
}
//销毁
void Destroylist(pList*pplist)
{
    pNode temp = NULL;
    assert(pplist);
    while (*pplist != NULL)
    {
        temp = (*pplist)->next;
        free(*pplist);
        *pplist = temp;
    }
}
//头插
void pushfront(pList*pplist, Datatype x)
{
    assert(pplist);
    pNode node = (pNode)malloc(sizeof(Node));
    if (node == NULL)
    {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    node->data = x;
    node->next = NULL;
    node->next = *pplist;
    *pplist = node;
}
//逆序打印
void Invert_display(pList pplist)
{
    if (pplist == NULL)
    {
        return;
    }
    if (pplist!= NULL)
    {
        Invert_display(pplist->next);
    }
    printf("%d-->", pplist->data);
}
//链表的逆序
void Invert_list(pList*pplist)
{
    assert(pplist);
    //保存当前要处理的节点的上一个节点的位置
    pNode temp = NULL;
    //当前要处理的节点位置
    pNode cur1 = *pplist;
    //保存当前要处理的节点的指向
    pNode cur2 = NULL;
    if (*pplist == NULL || (*pplist)->next == NULL)
        return;
    //当要处理的节点为空时,说明整个链表已经逆序完成。
    while (cur1 != NULL)
    {
        //保存当前节点的指向
        cur2 = cur1->next;
        //把当前节点的指向改为上一节点
        cur1->next = temp;
        //当前节点就成为下一个节点的的指向,所以提前保存起来
        temp = cur1;
        //使下次循环要处理的节点指向下一个节点
        cur1 = cur2;
    }
    *pplist = temp;
}
//合并两个有序链表非递归
pList Merge(pList*ls1, pList*ls2)
{
    assert(ls1&&ls2);
    pList New_list = NULL;
    pNode cur1 = *ls1;
    pNode cur2 = *ls2;
    pNode temp = NULL;
    pNode head = NULL;
    pNode tail = NULL;
    if (*ls1 == NULL&&*ls2 == NULL)
        return NULL;
    if (*ls1 == *ls2)
        return*ls1;
    if (*ls1 == NULL)
        return *ls2;
    if (*ls2 == NULL)
        return *ls1;
    if (cur1->data < cur2->data)
    {
        head = cur2;
        cur2 = cur2->next;
    }
    else
    {
        head = cur1;
        cur1 = cur1->next;
    }
    tail = head;
    tail->next = NULL;
    while (cur1 != NULL&&cur2 != NULL)
    {
        if (cur1->data < cur2->data)
        {
            tail->next = cur2;
            cur2 = cur2->next;
        }
        else
        {
            tail->next = cur1;
            cur1 = cur1->next;
        }
        tail = tail->next;
        tail->next=NULL;
    }
    if (cur1 == NULL)
        tail->next = cur2;
    else 
        tail->next = cur1;
    New_list = head;
    return New_list;
}
//递归合并两个有序链表,合并仍然是有序的
//从两个链表里挑出一个元素,并把他的地址返回去,最后一个一个元素串起来,形成一条新链表
pList _Merge(pList*ls1, pList*ls2)
{
    assert(ls1&&ls2);
    pNode cur1 = *ls1;
    pNode cur2 = *ls2;
    pNode head = NULL;
    //以下四个if语句进行特殊处理
    if (*ls1 == NULL&&*ls2 == NULL)
        return NULL;
    if (*ls1 == *ls2)
        return*ls1;
    if (*ls1 == NULL)
        return *ls2;
    if (*ls2 == NULL)
        return *ls1;
    //这个if语句在两个链表中跳出一个元素,把他的地址赋值给head
    if (cur1->data < cur2->data)
    {
        head = cur2;
        cur2 = cur2->next;
    }
    else
    {
        head = cur1;
        cur1 = cur1->next;
    }
    head->next = NULL;
    //如果两个链表没有处理完,就递归进行处理
    if (cur1 != NULL||cur2!=NULL)
        //用本次的head->next接受下一次处理好的节点的位置
        head->next = _Merge(&cur1, &cur2);
    //正常处理完之后返回处理的位置
    return head;
}
//删除一个非尾节点
void DelNotTail(pNode pos)
{
    pNode temp = NULL;
    pNode head = pos;
    if (head == NULL || head->next == NULL)
        return;
    //把该节点后面的节点内容覆盖到该节点,然后删除后面一个节点
    temp = head->next;
    head->data = head->next->data;
    head->next = head->next->next;
    free(temp);
}
//在一个位置前插入一个节点
void InsertFrontNode(pNode pos, Datatype x)
{
    pNode temp = (pNode)malloc(sizeof(Node));
    if (pos == NULL)
        return;
    if (temp == NULL)
    {
        perror("malloc");
        return;
    }
    //在该节点后面增加一个节点,交换两个节点数据,就相当于在该节点前面开辟一个节点一样
    temp->next = pos->next;
    pos->next = temp;
    temp->data = pos->data;
    pos->data = x;
}
//约瑟夫环
void JosephCycle(pList plist, int k)
{
    pNode temp = NULL;
    pNode head = plist;
    int count = k;
    if (plist == NULL)
        return;
    //删除后面节点法
    while (head!=head->next)
    {
        count = k;
        while (count- 1 > 0)
        {
            head = head->next;
            count--;
        }
        printf("%d ", head->data);
        temp = head->next;
        head->data = head->next->data;
        head->next = head->next->next;
        free(temp); 
    }
    删除当前节点
    //while (head != head->next)
    //{
    //  count = k;
    //  while (count - 2 > 0)
    //  {
    //      head = head->next;
    //      count--;
    //  }
    //  printf("%d ", head->next->data);
    //  temp = head->next;
    //  head->next = head->next->next;
    //  free(temp);
    //  head = head->next;
    //}
}
//寻找一个链表的中间节点,只能遍历一次
pNode FindMidNode(pList plist)
{
    pNode fast = plist;
    pNode slow = plist;
    if (fast == NULL)
        return NULL;
    while (fast!=NULL&&fast->next != NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}
//对链表的冒泡排序
void Bubblesort(pList  plist)
{
    pNode cur1 = plist;
    pNode cur2 = NULL;
    //每次循环的标记
    pNode flag = NULL;
    Datatype Datmp = 0;
    if (plist == NULL||plist->next == NULL)
        return;
    while (cur1->next != flag)
    {

        while (cur1->next!= flag)
        {
            if (cur1->data < cur1->next->data)
            {
                Datmp = cur1->data;
                cur1->data = cur1->next->data;
                cur1->next->data = Datmp;
            }
            cur1 = cur1->next;
        }
        flag = cur1;
        cur1 = plist;
    }
}
//删除倒数第k个元素
void DelKNode(pList *plist, int k)
{
    Node*node = *plist;
    Node*first = *plist;
    Node*slow = *plist;
    if (*plist == NULL)
        return;
    if (k <= 0)
        return;
    if (k == 1)
    {
        while (node->next != NULL&&node->next->next != NULL)
        {
            node = node->next;
        }
        if ((*plist)->next == NULL)
        {
            free(*plist);
            *plist = NULL;
            return;
        }
        free(node->next);
        node->next = NULL;
        return;
    }
    while (first!=NULL)
    {
        while (k)
        {
            first = first->next;
            k--;
        }
        if (k > 0)
        {
            return;
        }
        if (first != NULL)
        {
            first = first->next;
            slow = slow->next;
        }
    }
    slow->data = slow->next->data;
    Node*temp = slow->next;
    slow->next = slow->next->next;
    free(temp);
}
t plist)
{
    pNode Fast = plist;
    pNode Slow = plist;
    while (Fast != NULL&&Fast->next!=NULL)
    {
        Fast = Fast->next->next;
        Slow = Slow->next; 
        if (Slow == Fast)
        {
            return Fast;
        }
    }
    return NULL;
}
//求一个带环单链表环的长度
int GetCircleLength(pNode meet)
{
    pNode Fast = meet;
    pNode Slow = meet;
    int count = 1;
    while (1)
    {
        Fast = Fast->next->next;
        Slow = Slow->next;
        if (Fast == Slow)
        {
            return count;
        }
        count++;
    }
    return count;
}
//法一:求一个带环单链表环的入口点
pNode GetCircleEntreNode(pNode meet, pList plist)
{
    assert(meet&&plist);
    pNode First = plist;
    pNode second = meet;
    while (First != second)
    {
        First = First->next;
        second = second->next;
    }
    return First;
}
//法二:求一个带环单链表环的入口点
pNode _GetCircleEntreNode2(pList plist, int Length)
{
    assert(plist);
    pNode First = plist;
    pNode second = plist;
    while (1)
    {
        if (Length <= 0)
            second = second->next;
        First = First->next;
        if (First == second)
            break;
        Length--;
    }
    return First;
}
//判断两个不带环的单链表是否相交
pNode CheckCross(pList plist1, pList plist2)
{
    pNode head1 = plist1;
    pNode head2 = plist2;
    if (plist1 == NULL || plist2 == NULL)
        return NULL;
    while (head1->next != NULL)
    {
        head1 = head1->next;
    }
    while (head2->next != NULL)
    {
        head2 = head2->next;
    }
    if (head1 == head2)
        return head1;
    return NULL;
}
//求两个相交不带环单链表的交点
pNode GetCrossNode(pList plist1, pList plist2)
{
    pNode head1 = plist1;
    pNode head2 = plist2;
    pNode meet = NULL;
    pNode EntryCross = NULL;
    pNode tail = NULL;
    tail = CheckCross(head1,head2);
    if (tail == NULL)
        return NULL;
    //把一个链表的头,接到链表尾上,形成一个带环链表,变成求环的入口点问题
    tail->next = head1;
    meet = CheckCycle(head2);
    EntryCross =  GetCircleEntreNode(meet, head2);
    tail->next = NULL;
    return EntryCross;
}
//.c
#include"list.h"
//链表的逆序打印和链表的逆序
void test1()
{
    pList list = NULL;
    pushfront(&list, 1);
    pushfront(&list, 2);
    pushfront(&list, 3);
    pushfront(&list, 4);
    display(list);
    逆序打印
    //Invert_display(list);
    //链表元素的逆置
    Invert_list(&list);
    display(list);
    Destroylist(&list);
}
//合并两个有序链表
void test2()
{
    pList list1 = NULL;
    pList list2 = NULL;
    pList New_list = NULL;
    //第一链表list1
    pushfront(&list1, 0);
    pushfront(&list1, 2);
    pushfront(&list1, 4);
    pushfront(&list1, 6);
    pushfront(&list1, 8);
    pushfront(&list1, 10);
    //第二条链表
    pushfront(&list2, 1);
    pushfront(&list2, 3);
    pushfront(&list2, 5);
    pushfront(&list2, 7);
    New_list = _Merge(&list1, &list2);
    display(New_list);
    Destroylist(&list1);
    Destroylist(&list2);
}
//删除一个非尾节点
void test3()
{
    pList list = NULL;
    pushfront(&list, 1);
    pushfront(&list, 2);
    pushfront(&list, 3);
    pushfront(&list, 4);
    display(list);
    DelNotTail(find(list, 3));
    display(list);
    Destroylist(&list);
}
//指定节点前面添加一个节点
void test4()
{
    pList list = NULL;
    pushfront(&list, 1);
    pushfront(&list, 2);
    pushfront(&list, 3);
    pushfront(&list, 4);
    display(list);
    InsertFrontNode(find(list,3), 5);
    display(list);
    Destroylist(&list);
}
//约瑟夫环
void test5()
{
    pList list = NULL;
    pushfront(&list, 1);
    pushfront(&list, 2);
    pushfront(&list, 3);
    pushfront(&list, 4);
    pushfront(&list, 5);
    display(list);
    find(list, 1)->next = list;
    JosephCycle(list, 3);
}
//寻找一个链表的中间节点,只能遍历一次
void test6()
{
    pList list = NULL;
    pushfront(&list, 1);
    pushfront(&list, 2);
    pushfront(&list, 3);
    pushfront(&list, 4);
    pushfront(&list, 5);
    pushfront(&list, 6);
    printf("%d\n",FindMidNode(list)->data);
    Destroylist(&list);
}
//对链表的冒泡排序
void test7()
{
    pList list = NULL;
    pushfront(&list, 1);
    pushfront(&list, 3);
    pushfront(&list, 5);
    pushfront(&list, 2);
    pushfront(&list, 4);
    pushfront(&list, 6);
    pushfront(&list, 2);
    pushfront(&list, 5);
    pushfront(&list, 7);
    Bubblesort(list);
    display(list);
    Destroylist(&list);
}
//删除倒数第k个元素
void test8()
{
    pList list = NULL;
    pushfront(&list, 1);
    pushfront(&list, 2);
    pushfront(&list, 3);
    pushfront(&list, 4); 
    display(list);
    DelKNode(&list, 2);
    display(list);
    Destroylist(&list);
}
//带环单链表问题
void test9()
{
    pList list = NULL;
    //相遇点
    pNode meet = NULL;
    //入口点
    pNode EntryCross = NULL;
    //环的长度
    int Length = 0;
    pushfront(&list, 1);
    pushfront(&list, 2);
    pushfront(&list, 3);
    pushfront(&list, 4);
    pushfront(&list, 5);
    pushfront(&list, 6);
    pushfront(&list, 7);
    pushfront(&list, 8);
    pushfront(&list, 9);
    find(list, 1)->next = find(list,7);
    meet = CheckCycle(list);
    Length = GetCircleLength(meet);
    printf("环的长度为:%d\n", Length);
    printf("环的第一次相遇点为:%d\n", meet->data);
    //法一判断环入口点
    EntryCross = GetCircleEntreNode(meet, list);
    printf("环的r入口点为:%d\n", EntryCross->data);
    //法二判断入口点
    EntryCross = _GetCircleEntreNode2(list,Length);
    printf("环的r入口点为:%d\n", EntryCross->data);
    /*if (meet)
    {
        printf("带环\n");
    }
    else
    {
        printf("不带环\n");
    }*/
}
//两个不带环单链表相交问题
void test10()
{

    pList list1 = NULL;
    pList list2 = NULL;
    //是否相交的返回值
    pNode ret = 0;
    //链表的交点
    pNode CrossNode = NULL;
    pushfront(&list1, 1);
    pushfront(&list1, 2);
    pushfront(&list1, 3);
    pushfront(&list1, 4);
    pushfront(&list1, 5);
    pushfront(&list1, 6);
    pushfront(&list1, 7);
    pushfront(&list1, 8);
    pushfront(&list1, 9);
    pushfront(&list2, 10);
    pushfront(&list2, 11);
    pushfront(&list2, 12);
    find(list2, 10)->next = find(list1, 5);
    /*ret = CheckCross(list1, list2);
    if (ret != NULL)
        printf("相交\n");
    else
        printf("不相交\n");*/
    CrossNode = GetCrossNode(list1, list2);
    if (CrossNode!=NULL)
    printf("%d\n", CrossNode->data);
}
int main()
{
    test10();
    system("pause");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值