链表面试题(二)

本文所有的函数都是在上上一篇单链表和上一篇链表面试题(一)的基础上建立的。单链表链表面试题(一)

1、单链表排序(冒泡排序)

用三个指针来实现该功能,p1初始化为pHead,p2初始化为pHead->pNext,pEnd初始化为NULL,当p2不等于pEnd时,p1和p2的data进行比较,如果p1的data大于p2的data,p1和p2的值交换,否则p1和p2继续向后访问,pEnd指向pHead->pNext时,循环结束。
优化:创建一个标志位IsChange,如果交换将其置为1,当IsChange在一次循环中没有改变时,说明链表此时已经为有序链表,直接跳出循环。
这里写图片描述

函数实现源程序
Swap(int *x,int *y)
{
    int tmp = *x;
    *x = *y;
    *y = tmp;
}

//单链表排序(冒泡排序)
void BubbleSort(SList *pHead)
{
    SList *p1 = pHead;
    SList *p2 = pHead->pNext;
    SList *pEnd = NULL;
    int IsChange = 0;
    while(pEnd != pHead->pNext)
    { 
        IsChange = 0;
        p1 = pHead;
        p2 = pHead->pNext;

        while(p2 != pEnd)
        {
            if(p1->data > p2->data)
            {
                Swap(&(p1->data),&(p2->data));
                IsChange = 1;
            }
            p1 = p1->pNext;
            p2 = p2->pNext;
        }
        if(IsChange == 0)
            break;
        pEnd = p1;
    }
}
测试程序
void TestBubbleSort()
{
    SList *Head = NULL;
    Init(&Head);

    PushFront(&Head,1);
    PushFront(&Head,2);
    PushFront(&Head,3);
    PushFront(&Head,4);
    PushBack(&Head,11);
    PushBack(&Head,12);
    PushBack(&Head,13);
    PushBack(&Head,14);
    Print(Head);

    //单链表排序(冒泡排序)
    BubbleSort(Head);
    Print(Head);

    Destory(&Head);
}
执行结果:

这里写图片描述

2、合并两个有序链表,合并后依然有序

用两个指针分别指向两个链表,哪个小,就将哪个尾插到新的链表中,并向后走接着比较,当其中有一个链表结束,那么剩下的那个链表只需依次尾插到新链表即可。
这里写图片描述

函数实现源程序
//合并两个有序链表,合并后依然有序
SList *MergeSort(SList *pHead1,SList *pHead2)
{
    SList *pNode1 = pHead1;
    SList *pNode2 = pHead2;
    SList *pNode = NULL;
    SList *pResult = NULL;
    SList *pRemain = NULL;

    while(pNode1 != NULL && pNode2 != NULL)
    {
        if(pNode1->data > pNode2->data)
        {
            PushBack(&pResult,pNode2->data);
            pNode2 = pNode2->pNext;
        }
        else
        {
            PushBack(&pResult,pNode1->data);
            pNode1 = pNode1->pNext;
        }
    }
    if(pNode1 == NULL)
        pRemain = pNode2;
    else
        pRemain = pNode1;
    for(pNode=pRemain; pNode!=NULL; pNode=pNode->pNext)
    {
        PushBack(&pResult,pNode->data);
    }
    return pResult;
}
测试程序
void TestMergeSort()
{
    SList *Head1 = NULL;
    SList *Head2 = NULL;

    Init(&Head1);
    Init(&Head2);

    PushBack(&Head1,1);
    PushBack(&Head1,3);
    PushBack(&Head1,4);
    PushBack(&Head1,6);
    PushBack(&Head1,9);
    Print(Head1);

    PushBack(&Head2,0);
    PushBack(&Head2,1);
    PushBack(&Head2,2);
    PushBack(&Head2,4);
    PushBack(&Head2,5);
    PushBack(&Head2,9);
    PushBack(&Head2,11);

    Print(Head2);

    Print(MergeSort(Head1,Head2));//合并两个有序链表,合并后依然有序

    Destory(&Head2);
    Destory(&Head1);
}
执行结果:

这里写图片描述

3、求两个已排序单链表中相同的数据

思路和第二题相同,用两个指针来遍历两个链表,当两个链表的数据相同时,将其尾插到新链表。

函数实现源程序
//求两个已排序单链表中相同的数据
SList *UnionSet(SList *pHead1,SList *pHead2)
{
    SList *pNode1 = pHead1;
    SList *pNode2 = pHead2;
    SList *pNode = NULL;
    SList *pResult = NULL;

    while(pNode1 != NULL && pNode2 != NULL)
    {
        if(pNode1->data > pNode2->data)//如果pNode1->data大于pNode2->data,pNode2向后走
        {
            pNode2 = pNode2->pNext;
        }
        else if(pNode1->data < pNode2->data)//如果pNode1->data小于pNode2->data,pNode1向后走
        {
            pNode1 = pNode1->pNext;
        }
        else//如果pNode1->data等于pNode2->data,将该数尾插到pResult,pNode1和pNode2同时向后走
        {
            PushBack(&pResult,pNode1->data);
            pNode1 = pNode1->pNext;
            pNode2 = pNode2->pNext;
        }
    }
    return pResult;
}
测试程序
void TestUnionSet()
{   
    SList *Head1 = NULL;
    SList *Head2 = NULL;

    Init(&Head1);
    Init(&Head2);

    PushBack(&Head1,1);
    PushBack(&Head1,3);
    PushBack(&Head1,4);
    PushBack(&Head1,6);
    PushBack(&Head1,9);
    Print(Head1);

    PushBack(&Head2,0);
    PushBack(&Head2,1);
    PushBack(&Head2,2);
    PushBack(&Head2,4);
    PushBack(&Head2,5);
    PushBack(&Head2,9);
    PushBack(&Head2,11);

    Print(Head2);

    Print(UnionSet(Head1,Head2));//求两个已排序单链表中相同的数据

    Destory(&Head2);
    Destory(&Head1);
}
执行结果:

这里写图片描述

4、查找链表的中间节点,要求只能遍历一次链表

使用两个指针pSlow和pFast,pFast每次走两步,pSlow每次走一步,当pFast走完的时候,pSlow刚好走到链表的中间节点。

函数实现源程序
//查找链表的中间节点,要求只能遍历一次链表
SList *FindMiddle(SList *pHead)
{
    SList *pSlow = pHead;
    SList *pFast = pHead;
    assert(pHead != NULL);

    while(pFast != NULL)
    {
        pFast = pFast->pNext;
        if(pFast != NULL)
        {
            pFast = pFast->pNext;
        }
        else
        {
            break;
        }
        pSlow = pSlow->pNext;
    }
    return pSlow;
}
测试程序
void TestFindMiddle()
{
    SList *Head1 = NULL;

    Init(&Head1);

    PushBack(&Head1,1);
    PushBack(&Head1,3);
    PushBack(&Head1,4);
    PushBack(&Head1,6);
    PushBack(&Head1,9);
    Print(Head1);

    printf("%d\n",FindMiddle(Head1)->data);//查找中间节点

    Destory(&Head1);
}
执行结果:

这里写图片描述

5、查找单链表的倒数第K个节点,要求只能遍历一次链表

和第4题相同,仍然采用快慢指针的方法,要找倒数第K个节点,就让快指针先走K步,当快指针走完链表时,慢指针指向链表的倒数第K个节点。

函数实现源程序
//查找单链表的倒数第K个节点,要求只能遍历一次链表
SList *FindKNode(SList *pHead,int k)
{
    SList *pSlow = pHead;
    SList *pFast = pHead;
    int i = 0;
    for(i=0; i<k; i++)//快指针先走k步
    {
        pFast = pFast->pNext;
    }
    while(pFast != NULL)
    {
        pSlow = pSlow->pNext;
        pFast = pFast->pNext;
    }
    return pSlow;
}
测试程序
void TestFindKNode()
{   
    SList *Head1 = NULL;

    Init(&Head1);

    PushBack(&Head1,1);
    PushBack(&Head1,3);
    PushBack(&Head1,4);
    PushBack(&Head1,6);
    PushBack(&Head1,9);
    Print(Head1);

    printf("%d\n",FindKNode(Head1,2)->data);//查找倒数第k个节点

    Destory(&Head1);
}
执行结果:(找倒数第二个)

这里写图片描述

6、删除链表的倒数第K个

函数实现源程序
//删除链表的倒数第K个
void DeleteKNode(SList **ppHead,int k)
{
    SList *pPos = FindKNode(*ppHead,k);
    SList *pNode = *ppHead;
    if(pPos->pNext == NULL)//如果是尾节点就尾删
    {
        PopBack(ppHead);
    }
    else//否则删除一个非尾结点
    {
        DelNoTailNode(pPos);
    }
}
测试程序
void TestDeleteKNode()
{
    SList *Head1 = NULL;

    Init(&Head1);

    PushBack(&Head1,1);
    PushBack(&Head1,3);
    PushBack(&Head1,4);
    PushBack(&Head1,6);
    PushBack(&Head1,9);
    Print(Head1);

    DeleteKNode(&Head1,2);//删除倒数第k个节点
    Print(Head1);

    Destory(&Head1);
}
执行结果:(删除倒数第二个节点)

这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值