单链表倒置问题

数组作为存放同类数据的集合,给我们在程序设计时带来很多的方便,增加了灵活性。但数组也同样存在一些弊病。如数组的大小在定义时要事先规定,不能在程序中进行调整,这样一来,在程序设计中针对不同问题有时需要3 0个大小的数组,有时需要5 0个数组的大小, 难于统一。我们只能够根据可能的最大需求来定义数组,常常会造成一定存储空间的浪费。 我们希望构造动态的数组,随时可以调整数组的大小,以满足不同问题的需要。链表就是我们需要的动态数组。它是在程序的执行过程中根据需要有数据存储就向系统要求申请存储空间,决不构成对存储区的浪费。
下图是单链表的结构图:

这里写图片描述

单链表有一个头节点h e a d,指向链表在内存的首地址。链表中的每一个节点的数据类型为结构体类型,节点有两个成员:整型成员(实际需要保存的数据)和指向下一个结构体类型节点的指针即下一个节点的地址(事实上,此单链表是用于存放整型数据的动态数组)。链表按此结构对各节点的访问需从链表的头找起,后续节点的地址由当前节点给出。无论在表中访问那一个节点,都需要从链表的头开始,顺序向后查找。链表的尾节点由于无后续节点,其指针域为空,写作为N U L L。

链表中的各节点在内存的存储地址不是连续的,其各节点的地址是在需要时向系统申请分配的,系统根据内存的当前情况,既可以连续分配地址,也可以跳跃式分配地址。

单链表的创建过程有以下几步:
1 ) 定义链表的数据结构。

2 ) 创建一个空表。

3 ) 利用m a l l o c ( )函数向系统申请分配一个节点。

4 ) 将新节点的指针成员赋值为空。若是空表,将新节点连接到表头;若是非空表,将新 节点接到表尾。

5 ) 判断一下是否有后续节点要接入链表,若有转到3 ),否则结束。

下面直接上代码:


//链表结构体定义
typedef struct ListNode
{
   int data;
   struct ListNode *next;
}ListNode;

int n=0;//全部变量,用来存放链表个数
//创建链表
ListNode *createListNode()
{
   ListNode *head;
   ListNode *p1,*p2;
   p1=(ListNode*)malloc(sizeof(ListNode));
   p2=(ListNode*)malloc(sizeof(ListNode));
   head=NULL;
   printf("请输入要插入链表的数据:\n");
   scanf("%d",&p1->data);
   while(p1->data!=0)
   {
      ++n;//当data不为0时,则链表就增加一个数据
      if(n==1)
      {
         head=p1;
      }
      else
      {
         p2->next=p1;
      }
      p2=p1;//p1,p2指向同一个内存
      p1=(ListNode*)malloc(sizeof(ListNode));
      printf("请输入要插入链表的数据:\n");
      scanf("%d",&p1->data);
   }
   return head;
}

现在链表建立成功,那么如何对单链表倒置呢?下面介绍两种方法来对单链表进行倒置:

(1)递归方法:即将当前节点放入到下一节点之后

ListNode* reverse(ListNode *node)
{
    if(node==NULL)
    {
        return node;
    }
    if(node->next==NULL)
    {
        return node;
    }
    ListNode *preNode=reverse(node->next);

    ListNode *temp=node->next;

    temp->next=node;

    node->next=NULL;

    return preNode;
}

(2)非递归方法:即互相交换值

ListNode *Reverse(ListNode *node)
{
   if(node==NULL)
   {
      return node;
   }
   ListNode *prev=NULL;
   while(node->next!=NULL)
   {
      ListNode *tmp=node->next;
      node->next=prev;
      prev=node;
      node=tmp;
   }
}

(3)利用栈来实现:每经过一个结点的时候,把该节点放到一个栈中。当遍历完整个链表以后,再从栈顶开始逐个输出节点的值,此时输出的节点的顺序已经翻转过来了。

void PrintListReversingly_Iterator(ListNode* pHead)//利用栈实现(后进先出)
{
    stack<ListNode*> nodes;
    ListNode* pNode=pHead;
    while(pNode!=NULL)
    {
        nodes.push(pNode);
        pNode=pNode->m_pNext;
    }
    while(!nodes.empty())
    {
        pNode=nodes.top();
        printf("%d\t",pNode->m_nValue);
        nodes.pop();
    }
}

这个链表倒置问题虽然代码很简短,但是理解起来并不容易,希望大家可以在纸上画画图加深理解。

下面是完整的代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<stack>
using namespace std;

typedef struct ListNode{
    int m_nValue;
    ListNode* m_pNext;
}ListNode;

int n=0;
ListNode* CreateListNode()
{
   ListNode* phead;
   ListNode* p1,*p2;
   p1=(ListNode*)malloc(sizeof(ListNode));
   p2=(ListNode*)malloc(sizeof(ListNode));
   phead=NULL;
   printf("请输入要插入链表的数据\n");
   scanf("%d\n",&p1->m_nValue);
      while(p1->m_nValue!=0)
      {
          ++n;
          if(n==1)

         {
             phead=p1;
         }
          else{
             p2->m_pNext=p1;
          }
          p2=p1;
          p1=(ListNode*)malloc(sizeof(ListNode));
          printf("请输入要插入链表的数据\n");
          scanf("%d\n",&p1->m_nValue);
       }
       free(p1);
       p1=NULL;
       p2->m_pNext=NULL;
       printf("链表输入结束(END)\n");
   return phead;

}

void PrintListNode(ListNode *phead)
{
    ListNode* temp=phead;
    while(temp!=NULL)
    {

        printf("%d\n",temp->m_nValue);
        temp=temp->m_pNext;
    }
    printf("链表打印结束(END)\n");
}

ListNode* reverse(ListNode* node)//链表倒置(递归方法)
{
    if(node==NULL)
    {
        return node;
    }
    if(node->m_pNext==NULL)
    {
        return node;
    }
    ListNode *preNode=reverse(node->m_pNext);
    ListNode* temp=node->m_pNext;
    temp->m_pNext=node;
    node->m_pNext=NULL;
    return preNode;

}

ListNode *Reverse(ListNode* node)//非递归方法
{
    if(node==NULL)
    {
        return node;
    }
    ListNode* prev=NULL;
    while(node->m_pNext!=NULL)
    {
        ListNode* tmp=node->m_pNext;
        node->m_pNext=prev;
        prev=node;
        node=tmp;
    }
    return prev;
}

void PrintListReversingly_Iterator(ListNode* pHead)//利用栈实现(后进先出)
{
    stack<ListNode*> nodes;
    ListNode* pNode=pHead;
    while(pNode!=NULL)
    {
        nodes.push(pNode);
        pNode=pNode->m_pNext;
    }
    while(!nodes.empty())
    {
        pNode=nodes.top();
        printf("%d\t",pNode->m_nValue);
        nodes.pop();
    }
}

int main()
{
    ListNode* newNode=CreateListNode();
    //ListNode* reverse_Node=reverse(newNode);
    //PrintListNode(reverse_Node);
    PrintListReversingly_Iterator(newNode);
    system("pause");
    return 0;
}
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值