链表面试题(上)

原创 2018年01月04日 22:57:30

一、题目
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

版权声明:本文为博主原创文章,转载请私信博主。

链表面试题总结(一)

基于上一次写的链表,现在,我们来讨论下面这些问题。1.链表的冒泡排序 2.删除无头非尾节点 3.反转链表 4.在当前节点前插入一个数据x 5.查找链表的中间节点。 6.删除单链表的倒数第K个...
  • qq_26768741
  • qq_26768741
  • 2016年06月11日 12:06
  • 4061

【数据结构】链表的原理及与其相关的常见面试题总结

链表是一种数据结构,和数组同级。比如,Java中我们使用的ArrayList,其实现原理是数组。而LinkedList的实现原理就是链表了。链表在进行循环遍历时效率不高,但是插入和删除时优势明显。下面...
  • jianyuerensheng
  • jianyuerensheng
  • 2016年06月06日 09:49
  • 1340

面试考题之9.2:链表(C/C++版)

2.1 编写代码,移除未排序链表中的重复结点。进阶:如果不得使用临时缓冲区,该怎么解决? 解决方案: 方案1: 使用散列表 暂略 方案2:不借助额外缓冲区 1 2 3 4 5 6 7 8 ...
  • JohnnyHu90
  • JohnnyHu90
  • 2015年06月07日 16:35
  • 2500

链表面试题 解法总结

从尾打印链表 1 用递归的方法,如果当前节点不为空,继续调打印函数传过去的参数下一个节点。 If(PNode) {   Print_list(PNode->PNext);   Printf(“%d->...
  • sdoyuxuan
  • sdoyuxuan
  • 2017年04月04日 15:10
  • 465

链表常见面试题-C语言实现

前面的博客已经介绍过了实现链表的一些相关的功能,所以在这里就不对链表多加解释说明了。 对于链表相关面试题这里解释几个有特点的题: 1.对于求查找链表的中间结点,要求只能遍历一次链表? 方式:使用两个指...
  • IT_iverson
  • IT_iverson
  • 2017年08月03日 14:03
  • 1248

单链表面试题集合

1、找出单链表的倒数第K个元素(仅允许遍历一遍链表)      使用指针追赶的方法。定义两个指针fast和slow,fast先走K步,然后fast和slow同时继续走。当fast到链表尾部时,sl...
  • kqZhu
  • kqZhu
  • 2017年03月17日 10:10
  • 1413

常见的链表面试题大汇总:

常见的链表面试题大汇总: 源代码下载链接 1,创建一个链表结点 2,遍历链表中的所有结点 3,倒序打印链表 4,往链表末尾添加结点 5,往链表前端添加结点,6,获取链表的节点数目 7,销...
  • mengni123321
  • mengni123321
  • 2015年09月05日 20:57
  • 450

面试大总结之一:Java搞定面试中的链表题目

链表是面试中常出现的一类题目,本文用Java实现了面试中常见的链表相关题目。本文主要参考整合重写了《轻松搞定面试中的链表题目》和 《算法大全(1)单链表》两篇大作。两篇大神的实现分别是C和C#,因为我...
  • hellobinfeng
  • hellobinfeng
  • 2013年11月16日 05:53
  • 22758

单链表面试题——基础篇

1.比较顺序表和链表的优缺点,说说它们分别在什么场景下使用 总结: 1.若线性表需要频繁查找,很少进行插入、删除操作,宜采用顺序存储结构。若需要频繁插入和删除时,宜采用单链表结构; 2.当线性表...
  • sssssuuuuu666
  • sssssuuuuu666
  • 2017年06月13日 17:37
  • 472

链表总结----链表面试题合集

1、单链表基本操作 2、双链表基本操作 3、循环单链表基本操作 4、反转单链表 5、查找单链表倒数第K个节点 6、倒序打印链表 7、查找链表中间节点 8、删除链表第K个节点,平均时间复杂度为O(1) ...
  • beitiandijun
  • beitiandijun
  • 2014年12月13日 23:25
  • 1853
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:链表面试题(上)
举报原因:
原因补充:

(最多只允许输入30个字)