zoukankan      html  css  js  c++  java
  • 单向链表的反转(递归和非递归)

    一、非递归(从头开始反转)

    1、保存头指针的下一个节点(第一个元素),同时将头指针指向NULL

    2、从第一个元素节点开始while循环往后处理,将当前节点的下一个节点指向前一个节点

    3、最后再将头指针指向反转后的第一个元素节点

    举个例子,反转如下链表:

     1、(NewH是反转后链表的头指针

    2、

    3、

    4、一直这样循环处理,直到最后一步

    #include<iostream>
    #include<stdlib.h>
    using namespace std;
    struct node
    {
        int x;
        node* next;//指向结构体的一个指针
    };
    
    node *Head, *End;
    
    void add(int m)
    {
        node *temp = (struct node*)malloc(sizeof(struct node));//强制类型转换+分配地址空间
    
        //节点赋值,m是一个整数型的值,要把它变成结构体类型才能放进链表里
        temp->x = m;
        temp->next = NULL;
    
        if (Head== NULL)//头指针为空,说明链表为空,那么temp即是头指针,也是尾指针
        {
            Head = temp;
            End = temp;
        }
        else
        {
            //链表不为空的情况,让尾指针指向当前节点,同时尾指针后移,为下一次添加节点准备
            End->next = temp;
            End = temp;
    
            //上面的是尾插,即在链表尾部加入节点
            //如果在链表头部加入节点,让头指针指向当前节点,同时头指针前移就可以
    
            //Head->next=temp;
            //Head=temp;
        }
    
    
    }
    
    void change()
    {
        node *now=Head->next;//保存头指针后的第一个节点
        Head->next=NULL;//将头指针的下一个节点指向空
        node *temp=NULL;//temp是反转后的第一个节点的指针
        while(now!=NULL)
        {   
            node *tp=now->next;//tp保存下一个节点
            now->next=temp;
            temp=now;
            now=tp;
        }
        Head->next=temp;
    
    }
    
    int main()
    {
        Head = (struct node*)malloc(sizeof(struct node));
        End = (struct node *)malloc(sizeof(struct node));
        Head->next = NULL;
        End = Head;
        int n, m;
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>m;
            add(m);
        }
        change();
        node *temp=Head->next;
        while(temp!=NULL)
        {
            cout<<temp->x<<' ';
            temp=temp->next;
        }
        cout<<endl;
        return 0;
    }

    二、递归(从尾开始反转)

    1、通过now->next往下递归,直到最后一个节点

    2、将最后一个节点指向前一个节点,同时将反转后的表头指针指向NULL,一直处理到最后

    举个例子,同上链表

     

    首先指针H迭代到底如下图所示,并且设置一个新的指针作为翻转后的链表的头(NewH)。由于整个链表翻转之后的头就是最后一个数,所以整个过程NewH指针一直指向存放5的地址空间。

      然后H指针逐层返回的时候依次做下图的处理,将H指向的地址赋值给H->next->next指针

      继续返回操作:

      上图第一次如果没有将存放4空间的next指针赋值指向NULL,第二次H->next->next=H,就会将存放5的地址空间覆盖为3,这样链表一切都大乱了。接着逐层返回下去,直到对存放1的地址空间处理。

      返回到头:

    图片转载自:https://blog.csdn.net/FX677588/article/details/72357389

    #include<iostream>
    #include<stdlib.h>
    using namespace std;
    struct node
    {
        int x;
        node* next;//指向结构体的一个指针
    };
    
    node *Head, *End;
    void add(int m)
    {
        node *temp = (struct node*)malloc(sizeof(struct node));//强制类型转换+分配地址空间
    
        //节点赋值,m是一个整数型的值,要把它变成结构体类型才能放进链表里
        temp->x = m;
        temp->next = NULL;
    
        if (Head== NULL)//头指针为空,说明链表为空,那么temp即是头指针,也是尾指针
        {
            Head = temp;
            End = temp;
        }
        else
        {
            //链表不为空的情况,让尾指针指向当前节点,同时尾指针后移,为下一次添加节点准备
            End->next = temp;
            End = temp;
    
            //上面的是尾插,即在链表尾部加入节点
            //如果在链表头部加入节点,让头指针指向当前节点,同时头指针前移就可以
    
            //Head->next=temp;
            //Head=temp;
        }
    
    
    }
    
    node* find(node *now)
    {
        if(now==NULL||now->next==NULL)
            return now;
        else
        {
            node *pre=find(now->next);//先递归找now的后一个节点pre,直到pre->next为NULL(也就是说pre是倒数第二个节点)   
            //然后从后面开始往前反转
    
            now->next->next=now;//然后把pre的下一个节点指向now,这里就实现了反转
            now->next=NULL;//把当前节点指向空
            return pre;//pre是链表反转后的头指针
        }
    }
    int main()
    {
        Head = (struct node*)malloc(sizeof(struct node));
        End = (struct node *)malloc(sizeof(struct node));
        Head->next = NULL;
        End = Head;
        int n, m;
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>m;
            add(m);
        }
        node *temp=find(Head->next);
        while(temp!=NULL)
        {
            cout<<temp->x<<' ';
            temp=temp->next;
        }
        cout<<endl;
        return 0;
    }

    三、翻转区间[n,m]位置上的链表

    例如链表1->2->3->4->5->NULL

    翻转[2,4]

    翻转后为1->4->3->2->5->NULL

    #include<iostream>
    #include<string.h>
    using namespace std;
    
    struct ListNode
    {
        int x;
        ListNode *next;
    };
    
    ListNode* reverseBetween(ListNode* head, int m, int n) //head是无头指针链表,例如:1—>2->3->NULL
    {
        ListNode* res=(struct ListNode*)malloc(sizeof(struct ListNode));
        res->next=head;
        ListNode *pre=res;
        //找到第m-1个结点
        for(int i=1;i<m;++i)
        {
            pre=pre->next;
        }
        //找到第m个结点
        ListNode* cur=pre->next,*pm=pre->next;
        //利用头插法进行反转
        for(int i=m;i<=n;++i)
        {
            ListNode *temp=cur->next;//临时保存当前结点的下一个结点信息
            cur->next=pre->next;//pre->next是第m个位置的结点,相当于翻转链表的头指针
            pre->next=cur;//头指针后移
            cur=temp;
        }
        //第m个节点指向n+1个结点
        pm->next=cur;
        return res->next;
    }
    
    int main()
    {
        ListNode *head, *end;
        head = (struct ListNode*)malloc(sizeof(ListNode));
        end = (struct ListNode*)malloc(sizeof(ListNode));
        head->next = NULL;
        end = head;
        int t, n, m, x;
        cin >> t;
        cin >> n >> m;
        for (int i = 0; i < t; i++)
        {
            cin >> x;
            ListNode* temp = (struct ListNode*)malloc(sizeof(ListNode));
            temp->x = x;
            temp->next = NULL;
    
            end->next = temp;
            end = temp;
    
        }
        //cout<<head->x<<' '<<head->next->x<<endl;
        ListNode *temp = reverseBetween(head->next, n, m);
        while (temp!=NULL)
        {
            cout << temp->x << ' ';
            temp = temp->next;
        }
        cout << endl;
        return 0;
    }
  • 相关阅读:
    路由器桥接是个什么玩法
    MAC使用小技巧之------用好mac电脑的10个必知的小技巧!
    学习笔记1--响应式网页+Bootstrap起步+全局CSS样式
    mysql运维必会的一些知识点整理
    面试小结1--填空题
    CSS技术实例1-使用CSS计数器实现数值计算小游戏实例页面
    编译8.0
    解决Windows 10 1809 使用管理员权限运行的程序无法浏览网络驱动器的问题
    android sdk
    酷卓教程 明明已经已经有了面具Magisk 确无法正常使用root权限
  • 原文地址:https://www.cnblogs.com/-citywall123/p/12411439.html
Copyright © 2011-2022 走看看