• 单链表逆置


    方法一:非递归方法,利用辅助指针,时间复杂度为O(n)

    程序如下:

    template <typename Type>
    struct ListNode {
        Type data;
        ListNode* next;
        ListNode(Type pdata) :data(pdata), next(nullptr) {}
    };
    
    template <typename Type>
    void reverseList(ListNode *node)
    {
        ListNode *currPos = node, *nextPos = node->next, *prevPos = nullptr;
        while (nextPos != nullptr)
        {
            // 改变currPos->next
            currPos->next = prevPos;
    
            // 依次更新prev、curr、next(向后移动)
            prevPos = currPos;
            currPos = nextPos;
            nextPos = nextPos->next;
        }
        currPos->next = prevPos; // 注意最后一步
        return currPos;
    }

    上面的过程如果不画图的话,很容易搞晕,所以我绘制了下面的过程图便于理解:

    方法二:递归方法

    template <typename Type>
    struct ListNode {
        Type data;
        ListNode* next;
        ListNode(Type pdata) :data(pdata), next(nullptr) {}
    };
    
    template <typename Type>
    void reverseList_recur(ListNode *currPos)
    {
        // 空链表
        if (currPos == nullptr)
            return;
        // 基准情形,也就是递归结束条件
        if (currPos->next == nullptr)
            return;
        ListNode *nextPos = currPos->next;
    
        reverseList_recur(nextPos);
    
        nextPos->next = currPos;
        currPos->next = nullptr;
    }

    递归方法还是比较难以理解的,知道栈帧的概念的话会容易很多。每次函数调用都会在栈空间push一块空间,这个空间会保存该函数的形参和局部变量,当函数结束后,才会pop出这块空间。

    也就是说,每次递归调用中的形参 currPos,局部变量nextPos都保存下来,直到基准情形出现。会产生多个currPos、nextPos变量,加上函数调用产生的其他指针和空闲空间等等。会占用更多的内存空间,而且函数调用会产生更多操作,时间开销很大。当然,并不排除有些编译器会优化掉递归的函数调用过程。

    所以,递归方法并不推荐。递归的图示绘制相对复杂,这里不再演示。

  • 相关阅读:
    呵呵,庆祝偶的blog开张了~
    把.NET程序部署到没有安装.NETFramwork的机器上
    1842005 日记
    So In Love
    windows网络编程经典入门
    水木穿梭
    c++智能指针的使用,shared_ptr,unique_ptr,weak_ptr
    c++的左值(lvalue),右值(rvalue),移动语义(move),完美转发(forward)
    (一)深入理解JVM第三版JDK的发展历史
    处理在多参数情况下分页参数的完整性
  • 原文地址:https://www.cnblogs.com/sdlwlxf/p/4968895.html
Copyright © 2020-2023  润新知