线性表逆置--顺序表\单链表逆置


一、模板类

参考自《数据结构(用面向对象方法与c++语言描述)第2版》,殷人昆主编,有改动。

1.线性表

//线性表模板
template<class T>
class LinearList
{
public:
	LinearList() {}//构造函数
	~LinearList() {};//析构函数
	virtual int Size()const = 0;//求表最大体积
	virtual int Length()const = 0;//求表长度
	virtual int Search(T& x)const = 0;//在表中搜索给定值x
	virtual int Locate(int i)const = 0;//在表中定位元素x位置
	virtual T getData(int i)const = 0;//取第i个表项的值
	virtual void setData(int i, T& x) = 0;//修改第i个表项的值
	virtual bool Insert(int i, T& x) = 0;//在第i个表项后插入x
	virtual bool Remove(int i, T& x) = 0;//删除第i个表项,通过x返回
	virtual bool IsEmpty()const = 0;//判表空
	virtual bool IsFull()const = 0;//判表满
	virtual void Sort() = 0;//排序
	virtual void input() = 0;//输入
	virtual void output() = 0;//输出
};

2.顺序表

template<class T>
class SeqList :public LinearList<T>//使用整型的线性表,并以递增正数序列作为线性表的顺序
{
protected:
	T *A;//数组首地址
	int arrsize;//数组的最大容量
	int elenum;//最后元素的下标
	void reSize(int newSize);//改变顺序表大小
public:
	SeqList(int size = maxSize);//构造函数
	SeqList(SeqList<T>&L);
	~SeqList();//析构函数
	int Size()const;//最大容量
	bool getData(int i,T& x)const;//返回指定位置的数值
	int Length()const { return elenum; }//返回elenum
	bool IsFull()const override { return elenum == arrsize; }
	bool IsEmpty()const override { return elenum == -1; }
	int Search(T& x)const;//搜索x在表中位置
	int Locate(int i)const;//搜索第i个表项,返回表项序号
	void setData(int i, T& x);//设置第i项值
	bool Remove(int i, T& x);//删除,删除的元素通过x返回
	bool Insert(int i, T& x);//插入x到第i项
	void Sort();
	void input();
	void output();
};

3.单链表

template<class T>
struct LinkNode//结点
{
	T data;
	LinkNode<T> *link;
	LinkNode(LinkNode<T> *ptr = NULL) { link = ptr; }
	LinkNode(const T& item, LinkNode<T> *ptr = NULL) { data = item;link = ptr; }
};
template<class T>
class List
{
public:
	List() { first = new LinkNode<T>; }
	List(const T& x) { first = new LinkNode<T>(x); }
	List(List<T>& L);
	~List() { makeEmpty(); }
	void makeEmpty();//置空
	LinkNode<T> *Locate(int i)const;//第i个元素地址
	bool getData(int i, T& x)const;//获取第i个元素,通过x返回
	int Length()const;//链表长度
	LinkNode<T> *getHead()const { return first; }
	LinkNode<T> *Search(T x);//搜索含x的元素
	void setData(int i, T& x);//设置第i个结点为x
	bool Insert(int i, T& x);//在第i个结点后插入x
	bool Remove(int i, T& x);//移除第i个结点,通过x返回
	bool IsEmpty()const { return first->link == NULL ? true : false; }
	void Sort();//排序
	void input();//输入
	void output();//输出
protected:
	LinkNode<T> *first;
};

有两种思路进行逆置,分别是破坏性的逆置和构造性的逆置。

破坏性的逆置:对原有的储存结点进行逆置,调用方法后原线性表的结点顺序反转。

构造性的逆置:构造一个新的空间用于储存逆置顺序的线性表,不会影响原线性表的结点顺序。

二、顺序表逆置

1.破坏性逆置

代码如下:

template<class T>
void SeqList<T>::reverse()
{
	if (IsEmpty())
		return;
	for (int i = 1;i <= elenum / 2;i++)//检索半个链表
	{
		T temp = A[i];
		A[i] = A[elenum + 1 - i];
		A[elenum + 1 - i] = temp;
	}
}

分析:通过对称性,将第elenum(顺序表尾部元素下标)+1-i的元素与第i个元素的值互换。

2.构造性逆置

代码如下:

T* SeqList<T>::reverse()const
{
	if (IsEmpty())
		NULL;
	T* newList=new T[Length()];
	for (int i = 1;i <= elenum;i++)//注意顺序表中元素下标从1开始,而新数组下标从0开始
	{
		newList[i-1] = A[elenum + 1 - i];//赋值给新数组i-1位
	}
	return newList;
}

分析:思路和上面的相同,返回逆置数组头。


三.单链表逆置

说明:单链表采用附加头结点形式。

1.破坏性逆置

代码如下:

void List<T>::reverse()
{
	if (IsEmpty())
		return;
	LinkNode<T>* tail = Locate(Length());//保存当前尾结点
	while (Length() > 1)
	{
		LinkNode<T>* p = Locate(Length());//链表当前尾结点
		Locate(Length() - 1)->link = NULL;
		p->link = Locate(Length());//反指后,由于断开了一个结点,原来的length-1变为现在的length
	}
	first->link = tail;
}

分析:tail:指当前链表尾结点。Locate(Length())固定返回当前尾结点,由于该链表是附加头结点,所以循环条件设置为长度大于1。在循环中,使当前尾结点反指向上一个结点,最终得到的tail是逆置后链表的第一个结点。

2.构造性逆置

说明:返回无附加头结点的单链表

LinkNode<T>* reverse()const
	{
		if (IsEmpty())
			return NULL;
		LinkNode<T>* newHead = new LinkNode<T>(Locate(Length())->data);
		LinkNode<T>* newTail = newHead;
		for (int i = Length() - 1;i >= 1;i--)
		{
			LinkNode<T>* newNode = new LinkNode<T>(Locate(i)->data);
			newTail->link = newNode;
			newNode->link = NULL;
			newTail = newTail->link;//更新尾部定位
		}
		return newHead;
	}

分析:创建newHead作为新链表头部,newTail始终指向新链表尾部,利用Locate倒序遍历链表,获取结点插入到newTail后面,最后返回逆置链表头newHead。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值