线性链表的就地逆置算法

实现线性链表的就地逆置算法,即在原表的存储空间将线性表(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;
}

最后 

动态内存申请的问题,参考这篇文章

什么时候使用malloc

c++什么时候需要进行malloc【C知道】

在C++中,通常情况下不建议使用malloc函数进行内存分配。C++提供了更安全和方便的内存管理方式,如new和delete操作符。使用new操作符可以动态地分配内存,并调用构造函数初始化对象;而delete操作符则用于释放通过new分配的内存,并调用析构函数销毁对象。

然而,在某些特殊情况下,可能需要使用malloc函数进行内存分配。以下是一些可能需要使用malloc的情况:

  1. 与C代码的兼容性:如果你需要与C代码进行交互,或者使用C库函数,那么可能需要使用malloc来分配内存。因为C代码通常使用malloc进行内存分配。

  2. 动态数组:如果你需要动态地分配数组,但是数组大小在运行时才确定,那么可以使用malloc来分配内存。例如,当你需要一个可变大小的数组时,可以使用malloc来分配内存。

  3. 对象的内存对齐:在某些特殊情况下,可能需要手动控制对象的内存对齐方式。malloc函数可以分配指定对齐方式的内存块。

需要注意的,使用malloc函数进行内存分配后,必须手动释放内存,否则会导致内存泄漏。可以使用free函数来释放通过malloc分配的内存。

 

 

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值