链表面试题

一、题目
1、从尾到头打印单链表 (有四种方法)
2、删除一个无头单链表的非尾节点(不能遍历链表)
3、在无头单链表的一个节点前插入一个节点(不能遍历链表)
4、单链表实现约瑟夫环(JosephCircle)
5、逆置/反转单链表
6、单链表排序(冒泡排序&快速排序)
7、合并两个有序链表,合并后依然有序
8、查找单链表的中间节点,要求只能遍历一次链表
9、查找单链表的倒数第k个节点,要求只能遍历一次链表
10、删除链表的倒数第K个结点
二、各函数代码和运行结果
1、从尾到头打印单链表 (有四种方法)

void EndToFirstPrintNode(SListNode*ps) //正常从头到尾打印
{
    SListNode *cur=NULL;
    SListNode *tail=NULL;
    while (ps != tail)
    {
        cur=ps;
        while (tail != cur->_next)
            cur=cur->_next;

        printf("%d ",cur->_data);
        tail=cur;
    }
}

void EndToFirstPrintSListNode(SListNode *ps)  //链表的从尾到头打印,用动态顺序表保存数据。
{
    size_t i = 0;
    while (ps)
    {
         CheckFullSeqlist(&List);
         List.data[i++]=ps->_data;
         List.size++;
         ps=ps->_next;
    }
    PrintSList(&List);
}

void EndToFirstPrintSListNodeR(SListNode *ps)//递归打印
{
    if (NULL != ps->_next) //递归结束条件
        EndToFirstPrintSListNodeR(ps->_next);  //子问题
    printf("%d ",ps->_data);
}

void EndToFirstPrintSListNodeNon(SListNode *ps)  //逆置链表
{
    SListNode *prev;
    SListNode *cur;
    SListNode *tmp;
    cur=ps;  //保存头结点
    prev=cur->_next;  //保存下一个节点
    cur->_next=NULL;  //头结点变为尾节点,next=NULL
    while (NULL != prev)  
    {
        tmp=prev->_next;
        prev->_next=cur;
        cur=prev;
        prev=tmp;
    }
    ps=cur;  //尾节点变为头节点
    SListPrint(ps);  //打印链表
}

运行结果:
这里写图片描述
2、删除一个无头单链表的非尾节点(不能遍历链表)

void NoHeadSeqListDelete(SListNode *pos) //删除一个无头链表的非尾节点(不能遍历链表)
{
    SListNode*tmp; 
    assert(pos);
    tmp=pos->_next;  //保存pos->_next的值,方便一会销毁
    pos->_data=pos->_next->_data;
    pos->_next=pos->_next->_next;
    free(tmp);  //销毁pos->_next
    tmp=NULL;
}

运行结果:
这里写图片描述
3、在无头单链表的一个节点前插入一个节点(不能遍历链表)

//创建一个新节点,替换原来的插入节点的值,再把插入值赋给原节点
void NoHeadSeqListInsert(SListNode*pos,DataType x) //在无头链表的一个节点前插入一个节点(不能遍历链表)
{
    SListNode *newNode;
    newNode=BuySListNode(x);  //创建新节点
    newNode->_next=pos->_next;  
    pos->_next=newNode;
    newNode->_data=pos->_data;
    pos->_data=x;
}

运行结果:
这里写图片描述
4、单链表实现约瑟夫环(JosephCircle)

void JosephCircle(SListNode*ps)  //约瑟夫环问题
{
    int k = 0;
    SListNode *tmp=ps;
    SListNode*cur=NULL;
    while (tmp->_next)
    {
        tmp=tmp->_next;
    }
    tmp->_next=ps;   //链接为一个环
    while (ps!=ps->_next)
    {
        ps=ps->_next;
        k++;
        if (k==2)  //每走三步杀一个
        {
            cur=ps->_next;
            ps->_next=ps->_next->_next;
            k=0;
            free(cur);
            cur=NULL;
        }
    }
    printf("%d\n",ps->_data);
}

运行结果:
这里写图片描述
5、逆置/反转单链表

SListNode* ReverseSeqList(SListNode *Seq) //逆置/反转单链表 
{
    SListNode *prev=Seq; //保存头节点
    SListNode *cur=prev->_next;  //保存第二个节点
    SListNode *tmp;
    assert(Seq);
    prev->_next=NULL;  //置空头节点的next,变成尾节点
    while (cur!=NULL)  //循环逆置 
    {
        tmp=cur->_next;  
        cur->_next=prev;
        prev=cur;
        cur=tmp;
    }
    Seq=prev;  //逆置后的头
    return Seq;
}

运行结果:
这里写图片描述
6、单链表排序(冒泡排序)

void SeqListSort(SListNode *Seq)//单链表排序(冒泡排序)
{
    SListNode *tail,*tmp=Seq;
    DataType flag=0;
    assert(Seq);
    if (Seq->_next==NULL||Seq==NULL)  //防止是空链表或者只有一个节点
    {
        return;
    }
    while (tmp!=NULL)  //找尾节点
    {
        tmp=tmp->_next;
    }
    tail=tmp;  
    while (tail!=Seq)
    {
        tmp=Seq;  //重置头节点
        while (tmp->_next!=tail)
        {
            if (tmp->_data>tmp->_next->_data)    //循环冒泡
            {
                flag=1;
                tmp->_data^=tmp->_next->_data;
                tmp->_next->_data^=tmp->_data;
                tmp->_data^=tmp->_next->_data;
            }
            tmp=tmp->_next;  //循环后移
        }
        if (flag==0)  //优化冒泡次数
        {
            break;
        }
        tail=tmp; //尾前移
    }
}

这里写图片描述
7、合并两个有序链表,合并后依然有序

SListNode* SListMerge(SListNode *list1,SListNode *list2)//合并两个有序链表,合并后依然有序 
{
    SListNode *list,*tmp;
    assert(list1&&list2);
    if (list1->_data<list2->_data)  //找到两个链表中小的一个头节点
    {
        list=list1;
        list1=list1->_next;
    }
    else
    {
        list=list2;
        list2=list2->_next;
    }
    tmp=list; //将小的一个链表头节点作为新链表的节点
    while (NULL!=list1 && NULL!=list2)  //循环比较,取两链表中小的节点链给list
    {
        if (list1->_data<list2->_data)
        {
            list->_next=BuySListNode(list1->_data);  //
            list1=list1->_next;
            list=list->_next;
        }
        else
        {
            list->_next=BuySListNode(list2->_data);
            list2=list2->_next;
            list=list->_next;
        }
    }
    if (NULL==list1)  //取出剩下一个量表后面所有连接给list
    {
        list->_next=list2;
    }
    else
    {
        list->_next=list1;
    }
    return tmp; //返回新链表的头节点地址
}

运行结果:
这里写图片描述
8、查找单链表的中间节点,要求只能遍历一次链表

SListNode* SListFindMidNode(SListNode* list) //查找单链表的中间节点,要求只能遍历一次链表
{
    SListNode *fast;
    SListNode *slow;
    assert(list);
    fast=slow=list; 
    //如果链表没节点,一个或者两个节点,直接返回头节点
    if (NULL==list || NULL==list->_next || NULL==list->_next->_next)      
    {
        return list;
    }
    while (fast) //快指针走到尾,慢指针走到中间。
    {
        fast=fast->_next->_next;  //快指针一次走两步 
        slow=slow->_next;  //慢指针一次走一步
    }
    return slow; //返回中间节点的地址
}

运行结果:
这里写图片描述
9、查找单链表的倒数第k个节点,要求只能遍历一次链表

//查找单链表的倒数第k个节点,要求只能遍历一次链表
SListNode* SListFindTailKNode(SListNode *list, size_t k) 
{
    SListNode *fast;
    SListNode *slow;
    assert(list);
    fast=slow=list;
    while (--k)  //快指针走k-1步
    {
        if (NULL==fast) //少于k个节点,直接返回首地址
        {
            return list;
        }
        fast=fast->_next;  
    }
    while (fast->_next)  //快慢指针循环后移
    {
        slow=slow->_next;
        fast=fast->_next;
    }
    return slow;//返回倒数第k个节点的地址
}

运行结果:
这里写图片描述
10、删除链表的倒数第K个结点

void DeleteKNode(SListNode *list,size_t k)//删除链表的倒数第K个结点
{
    SListNode *fast,*slow,*tmp;
    assert(list);
    fast=slow=list;
    while (--k)  //快指针走k-1步
    {
        if (NULL==fast) //少于k个节点,直接返回首地址
        {
            return;
        }
        fast=fast->_next;  
    }
    while (fast->_next)  //快慢指针循环后移,找到第k个节点
    {
        tmp=slow;  //保存第k个节点的前继
        slow=slow->_next;
        fast=fast->_next;
    }
    tmp->_next=slow->_next;  //链接上第k个节点后面的节点
    free(slow);  //释放掉第k个节点
    slow=NULL;
}

运行结果:
这里写图片描述
三、整体代码和测试代码:
整体代码和测试代码在另一篇博客里(http://blog.csdn.net/qq_38646470/article/details/78976498

  • 8
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙跃十二

写的不错,给点鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值