zoukankan      html  css  js  c++  java
  • 单链表的逆置(头插法和就地逆置)

    今天课间的时候偶然看到了一个面试题:单链表的逆置,看了题解感觉乖乖的,貌似和以前看的版本不搭,于是重新进行了一番探究

    单链表的逆置分为两种方法:头插法和就地逆置法,这两种方法虽然都能够达到逆置的效果,但还是有着不小的差别

    头插法

          

    算法思路:依次取原链表中的每一个节点,将其作为第一个节点插入到新链表中,指针用来指向当前节点,p为空时结束。 
    核心代码

    void reverse(node*head)
    {
        node*p;
        p=head->next;
        head->next=NULL;
        while(p)
        {
            q=p;
            p=p->next;
            q->next=head->next;
            head->next=q;
        }
    } 

    以上面图为例子,说白了就是不断的将1后面的节点插入到head后面,即为头插法

    完整代码

    #include<stdio.h>
    #include<malloc.h>
    typedef struct node
    {
        int data;
        struct node*next;
     }node;
     node*creat()
     {
        node*head,*p,*q;
        char ch;
        head=(node*)malloc(sizeof(node));
        q=head;
        ch='*';
        puts("单链表尾插法,?结束");
        while(ch!='?')
        {
            int a; 
            scanf("%d",&a);
            p=(node*)malloc(sizeof(node));
            p->data=a;
            q->next=p;
            q=p;
            ch=getchar();
         }
         q->next=NULL;
         return(head);
     }
     void print(node*a)
     {
        puts("print ");
        a=a->next;
        while(a!=NULL)
        {
            printf("%d ",a->data);
            a=a->next;
         }
      }
     void reverse(node*head)
    {
        node*p,*q;
        p=head->next;
        head->next=NULL;
        while(p)
        {
            q=p;
            p=p->next;
            q->next=head->next;
            head->next=q;
        }
    } 
     main()
     {
        node*a;
        a=creat();
        print(a);
        reverse(a);
        puts("
    haved reversed:"); 
        print(a);
         return 0;
     }
    View Code

    程序截图 

          

    就地逆置法

    //单链表定义 
    typedef struct ListNode{ 
    int m_nValue; 
    ListNode* pNext; 
    };

    //单链表逆置实现

    ListNode* ReverseList(ListNode* pHead)
    {
        if (pHead == NULL || pHead->pNext == NULL)
        {
            retrun pHead;
        }
    
        ListNode* pRev = NULL;
        ListNode* pCur = pHead;
        while(pCur != NULL)
        {
            ListNode* pTemp = pCur;   // 步骤①
            pCur = pCur->pNext;       // 步骤②
            pTemp->pNext = pRev;      // 步骤③
            pRev = pTemp;
        }
        return pRev;
    }

        具体流程参见博客:http://www.cnblogs.com/dhls231/p/4773555.html       

              链表的翻转是程序员面试中出现频度最高的问题之一,常见的解决方法分为递归和迭代两种。最近在复习的时候,发现网上的资料都只告诉了怎么做,但是根本没有好好介绍两种方法的实现过程与原理。所以我觉得有必要好好的整理一篇博文,来帮忙大家一步步理解其中的实现细节。
      我们知道迭代是从前往后依次处理,直到循环到链尾;而递归恰恰相反,首先一直迭代到链尾也就是递归基判断的准则,然后再逐层返回处理到开头。总结来说,链表翻转操作的顺序对于迭代来说是从链头往链尾,而对于递归是从链尾往链头。
         具体实现可以参考这个博主:https://blog.csdn.net/FX677588/article/details/72357389

     整体实现代码:

    #include<iostream>
    using namespace std;
    
    struct node{
        int val;
        struct node* next;
        node(int x) :val(x){}
    };
    /***非递归方式***/
    node* reverseList(node* H)
    {
        if (H == NULL || H->next == NULL) //链表为空或者仅1个数直接返回
            return H;
        node* p = H, *newH = NULL;
        while (p != NULL)                 //一直迭代到链尾
        {
            node* tmp = p->next;          //暂存p下一个地址,防止变化指针指向后找不到后续的数
            p->next = newH;               //p->next指向前一个空间
            newH = p;                     //新链表的头移动到p,扩长一步链表
            p    = tmp;                   //p指向原始链表p指向的下一个空间
        }
        return newH;
    }
    /***递归方式***/
    node* In_reverseList(node* H)
    {
        if (H == NULL || H->next == NULL)       //链表为空直接返回,而H->next为空是递归基
            return H;
        node* newHead = In_reverseList(H->next); //一直循环到链尾 
        H->next->next = H;                       //翻转链表的指向
        H->next = NULL;                          //记得赋值NULL,防止链表错乱
        return newHead;                          //新链表头永远指向的是原链表的链尾
    }
    int main()
    {
        node* first = new node(1);
        node* second = new node(2);
        node* third = new node(3);
        node* forth = new node(4);
        node* fifth = new node(5);
        first->next = second;
        second->next = third;
        third->next = forth;
        forth->next = fifth;
        fifth->next = NULL;
        //非递归实现
        node* H1 = first;
        H1 = reverseList(H1);    //翻转
        //递归实现
        node* H2 = H1;    //请在此设置断点查看H1变化,否则H2再翻转,H1已经发生变化
        H2 = In_reverseList(H2); //再翻转
    
        return 0;
    }
    Java半颗糖
  • 相关阅读:
    java8 parallel并行处理实战
    java相关技术问答(二)
    [安卓基础] 007.管理Activity的生命周期
    [Python基础]009.os模块(1)
    [Objective-C] 012_数据持久化_XML属性列表,NSUserDefaults
    SD.Team团队人物形象
    读Pyqt4教程,带你入门Pyqt4 _013
    [Objective-C] 011_数据持久化_NSKeyedArchiver
    [Objective-C] 010_Foundation框架之NSSet与NSMutableSet
    [JavaWeb基础] 007.Struts2的配置和简单使用
  • 原文地址:https://www.cnblogs.com/2019wxw/p/10887783.html
Copyright © 2011-2022 走看看