实现线性链表的就地逆置算法,即在原表的存储空间将线性表(a1,a... an)逆置为(an, an-1. a1)。
首先
是深拷贝和浅拷贝的问题。最初的思路是采用深拷贝,这样会导致中间链表断开。
可参考这篇文章深拷贝和浅拷贝
其次
是编程问题。
思路很清晰:
1、创建一个链表
其中,关于结构体的创建,可以参考这篇文章结构体指针的定义和使用
typedef struct LNode{
int data;
LNode* next;
}LNode,*LinkList; //ListList为指向结构体LNode的指针类型
//后插法创建单链表
LinkList Create(int n)
{
LinkList L=new LNode;
L->next=NULL; //创建一个带头结点的空链表
LinkList r=L; //尾指针r,永远指向最后一个节点,初始指向头结点
for(int i=0;i<n;i++)
{
LinkList p=new LNode; //新结点
cin>>p->data;
p->next=NULL;
r->next=p; //尾指针指向的是链表最后一个节点,此时在最后插入新创建的p节点
r=p; //尾指针始终指向链表的最后一个节点
}
return L;
}
2、逆置链表
其中,不懂LinkList &L的区别可参考这篇文章LinkList L 与LinkList &L
//逆置链表
void reveser(LinkList &L)
{
LinkList a=L->next;
LinkList b=a->next;
a->next=NULL; //首先将a->next置空!这样创建好链表后,链表的最后一个节点的next仍为NULL
while(b!=NULL)
{
LinkList c=b->next; //循环进行时,c永远指向b的下一个节点,然后a,b往后移动
b->next=a;
a=b;
b=c;
}
//循环结束后,L->next指向链表尾部,a指向链表的头部
L->next=a;
}
3、打印单链表
//打印单链表
void Print_List(LinkList L)
{
LinkList p=L->next;
while(p)
{
cout<<p->data<<endl;
p=p->next;
}
}
4、main函数
int main()
{
LinkList L=Create(5);
cout<<"初始链表:"<<endl;
Print_List(L); //打印初始链表
cout<<"逆置后的链表:"<<endl;
reveser(L); //进行逆置
Print_List(L);
return 0;
}
如果不额外创建其他函数,只使用main函数
#include <iostream>
using namespace std;
typedef struct LNode{
int data;
LNode* next;
}LNode,*LinkList; //ListList为指向结构体LNode的指针类型
int main()
{
int n=5;
LinkList L=new LNode;
L->next=NULL; //创建一个带头结点的空链表
LinkList r=L; //尾指针r,永远指向最后一个节点,初始指向头结点
for(int i=0;i<n;i++)
{
LinkList p=new LNode; //新结点
cin>>p->data;
p->next=NULL;
r->next=p; //尾指针指向的是链表最后一个节点,此时在最后插入新创建的p节点
r=p; //尾指针始终指向链表的最后一个节点
}
LinkList a=L->next;
LinkList b=a->next;
a->next=NULL; //首先将a->next置空!这样创建好链表后,链表的最后一个节点的next仍为NULL
while(b!=NULL)
{
LinkList c=b->next; //循环进行时,c永远指向b的下一个节点,然后a,b往后移动
b->next=a;
a=b;
b=c;
}
//循环结束后,L->next指向链表尾部,a指向链表的头部
L->next=a;
//进行打印
cout<<"逆置后的链表:"<<endl;
LinkList p=L->next;
while(p)
{
cout<<p->data<<endl;
p=p->next;
}
return 0;
}
最后
动态内存申请的问题,参考这篇文章
c++什么时候需要进行malloc【C知道】
在C++中,通常情况下不建议使用malloc函数进行内存分配。C++提供了更安全和方便的内存管理方式,如new和delete操作符。使用new操作符可以动态地分配内存,并调用构造函数初始化对象;而delete操作符则用于释放通过new分配的内存,并调用析构函数销毁对象。
然而,在某些特殊情况下,可能需要使用malloc函数进行内存分配。以下是一些可能需要使用malloc的情况:
与C代码的兼容性:如果你需要与C代码进行交互,或者使用C库函数,那么可能需要使用malloc来分配内存。因为C代码通常使用malloc进行内存分配。
动态数组:如果你需要动态地分配数组,但是数组大小在运行时才确定,那么可以使用malloc来分配内存。例如,当你需要一个可变大小的数组时,可以使用malloc来分配内存。
对象的内存对齐:在某些特殊情况下,可能需要手动控制对象的内存对齐方式。malloc函数可以分配指定对齐方式的内存块。
需要注意的,使用malloc函数进行内存分配后,必须手动释放内存,否则会导致内存泄漏。可以使用free函数来释放通过malloc分配的内存。