zoukankan      html  css  js  c++  java
  • 单链表--链表

    大家好,本篇博客将讲述单链表的逆序,希望大家在看这篇博客的时候,手里拿张纸,手写一下过程!!!

    出现情况:第一轮基础笔试或者是技术一面

    难度系数:中

    面试题目:实现一个单链表的反转。例如:10  9   8   7   6   5   4   3   2   1

    反转之后应为:1   2   3   4    5   6   7   8   9   10

    要求10分钟之内写出代码,注意代码风格以及时间复杂度

    考点分析

    (1)基本概念:链表基础,代码规范问题,代码健壮性问题

    (2)对时间复杂度敏感

    解题思路:“一问,二画,三答”

    其实对于这个问题,我们下面先给出解题思路的几种方式,来解释为什么要先问清楚(首先要问清楚面试官侧重的是什么)!!!

    下面以角色的身份来阐述本问题的思路

    1.小张

    “我学过链表的基本操作,我可以重新申请一个链表,利用链表的前插法(头插法),这样就可以实现了链表的反转,我的思路是这样的。”

    我重新从创建空表开始,一个一个将链表的结点插入到新开辟的链表的表头,也就是头结点之后,如下图看我的思路。

    我还写好了算法了呢,看下面

    LinkList  ReverseList(LinkList &L){
        //从表尾到表头逆向建立单链表L,每次均在头结点之后插入元素
        LNode *s;int x;
        L=(LinkList)malloc(sizeof(LNode));  //创建头结点
        L->next=NULL;  //初始为空链表
        scanf("%d", &x);  //输入结点的值
        while(x!=9999) {  //输入 9999 表示结束
            s=(LNode*)malloc(sizeof(LNode) );  //创建新结点
            s->data-x;
            s->next=L->next;
            L->next=s;  //将新结点插入表中,L为头指针
            scanf ("%d", &x);
        }  //while 结束
        return L;
    }

    2.小杨

    “是的,你上面的代码可以实现要求,不过,我觉得空间复杂度为比较大,我有一个方法,借助三个指针来实现,下面是我的思路”

    上面是我的思路,下面是我的核心代码,代码和上面思路完全一样

    LinkList reverse_link(LinkList list){
        if (NULL == list || NULL == list->next)
            return list;
        LinkList temp ,preV,next;
        preV = list;
        temp = list->next;
        preV->next = NULL;
        
        while (temp != NULL) {
            next = temp->next;
            temp->next = preV;
            preV = temp;
            temp = next;
        }
        return prev;
    }

    这个代码的时间复杂度为O(n),另外仅仅申请了两个变量来存储额外信息。

    3.小糊涂

    “我和你们的思路都不一样,你看看所有的都是后移后移,

    如果我们把当前的结点逆序,我们先可以这样,把它的后继结点都逆序了,然后再把逆序好的尾结点的next指针再指向当前结点就好了吗”

    这样就需要比较少的代码啦,在这个里面要注意一点递归出口,在这里我是把链表为空或者链表只有一个结点当作递归的出口,下面是我的代码,代码比较简洁

    list *reverse(list *p, list *&head)
    {
        if(p == NULL || p->next == NULL)
        {
            head = p;
            return p;
        }
        else
        {
            list *temp = reverse(p->next, head);
            temp->next = p;
            return p;
        }
    }

    4.小孙

    上面利用递归操作(也是栈的应用),实际上可以很好的解决问题,我的思路也是利用栈操作,使用栈的先进后出特性,完成对链表的逆序输出。

    下面是我的代码,思路大家看代码就会清楚

    //逆向输出
    stack<int> reOutput(LinkNode *linkNode) {
    LinkNode *head;
    stack<int> s;
    head = linkNode;
    while (head != NULL) {
    s.push(head->value);
    head = head->next;
    }
    return s;
    }
    
    stack<int> s;
    s = reOutput(linkNode);
    while (!s.empty()) {
    cout << s.top() << endl;
    s.pop();
    }

    通过上面先压栈,然后再出栈,自定义栈的大小,可以很好的解决问题,据听说,这是很多大公司采取的方案!!!

    5.老师发言

    当大家碰到这个题目的时候,首先要问明白这个出题人的思想,问清楚是否对链表做出限制

    (1)如果说不能更改链表的结构,显然第二种方法就不行了,如果对链表的结构没有什么要求,这个方法还是很好的,毕竟时间复杂度为O(n),空间复杂度为常数S(1)

    (2)如果数据比较繁多,虽然递归操作代码量比较少,但是可能会导致栈溢出(而且问题也比较难排查出),所以递归有这个风险,如果能克服这个风险,递归也是个不错的选择。

    (3)假如有100w条数据,可能会导致栈溢出,我们可以利用栈操作,因为栈的特性是先进后出,所以就可以很好的解决了这个倒序问题,而且我们自定义栈,栈溢出,也被考虑到了。

    (4)至于头插法,如果时间复杂度和空间复杂度不要求,应该是个比较容易理解的过程。

    所以各有千秋,大家主要是了解思想,代码很好写。

  • 相关阅读:
    模块
    python运算符与表达式
    subShell与代码块
    参数展开与特殊字符
    变量和参数
    shelll Test
    Cypher查询语言--Neo4j 入门 (一)
    那些争议最大的编程观点
    大型网站架构不得不考虑的10个问题
    大型网站架构演变
  • 原文地址:https://www.cnblogs.com/guohai-stronger/p/9264609.html
Copyright © 2011-2022 走看看