(1小时数据结构)数据结构c++版本(一)--- 线性表数组表达

本例子是《数据结构与算法c++描述》中的线性表中抽象数据类型 (abstract data type, ADT):

目录

基本概念:

构造函数与析构函数:

是否为空:

Find函数:

查找函数:

删除数据:

插入函数:

输出函数与重构 << 符号输出:

题目部分函数:

changeSize函数:

Reverse函数:

复制构造函数:

操作函数:

线性交叉函数:

Merge函数:

Split函数:

测试程序:


基本概念:

先看基本类型吧:

(1小时数据结构)数据结构c++版本(一)--- 线性表数组表达_第1张图片

(1小时数据结构)数据结构c++版本(一)--- 线性表数组表达_第2张图片

      本例子采用了类模板,这里提醒一下大家,不要把定义与实现一个写在.h与.cpp, 因为模板的性质,当你在别的文件使用的时候,就会报无法解析外部符号的错误。

      本例子代码是书上的代码,后边的新加的功能是课后习题需要开发的,同时也对这个程序完善了一部分。

首先我们先看类的定义:

listearLine.h 文件中

/*
数组结构中的线性表数组样式

对应书中代码:数据结构算法与应用c++描述

程序编写:比卡丘不皮

编写时间:2020年6月24日 13:51:23

*/
#pragma once
#include 
#include "all_error.h"
#include 
using namespace std;

template
class LinearList
{
public:
	LinearList();
	LinearList(int MaxListSize ); //构造函数默认为
	~LinearList();                    //析构函数
	LinearList(const LinearList & L);  //复制构造函数
	bool IsEmpty()const;              //判断是否为空
	int Length() const { return length; }  //返回表的长度,即表中元素个数 
	bool Find(int k, T& x)const; //返回第k个元素至x中 若不存在第k个元素,则返回false
	int Search(const T& x) const; // 返回x所在位置 如果x 不在表中,则返回0
	LinearList& Delete(int k, T& x); // 删除第k个元素并将它返回至x中
	LinearList& Insert(int k, const T& x); // 在第k个元素之后插入x
	//改变数组最大长度函数,l为数组长度,m为数组最大长度
	LinearList& changeSize(T * elementNew, int nlength, int max); 
	LinearList& Reverse();  //元素次序的反转 element[k]=element[length-k]
	LinearList& Half();  //数组减半
	void Reset() { current = 1; } //设置数据位
	bool Current(T &x);     //返回当前的值
	bool End()const;       //是否为最后边
	bool Front() const;   //是否为最前边
	void Next();        //到下个值
	void Previous();    //到前一个值
	void clear();
	//线性表交叉组合
	LinearList& Alternate(const LinearList & list1, const LinearList & list2);
	//有规律(元素从小到大排列)线性表的组合
	LinearList& Merge(const LinearList & list1, const LinearList & list2);
	//线性表分割函数
	void Split(LinearList & list1, LinearList & list2);

	void Output(ostream& out) const; // 输出函数
	LinearList & operator =(const LinearList & x); //重载赋值运算
private:
	int length;   //数组的长度
	int MaxSize;  //数组最大值
	T * element; //一维动态数组
	int current;  //元素当前的位置
};

这里先讲下 

#include "all_error.h"

这里我写了抛出的异常类:

/*
线性表中的数组结构

对应书中代码:数据结构算法与应用c++描述

程序编写:比卡丘不皮

编写时间:2020年6月24日 13:51:23

*/
#pragma once

#include 
using namespace std;

class Noman
{
public:
	Noman()
	{
		cout << "内存不足"<< endl;
	}
	~Noman()
	{

	}
};

//使new引发NoMemory异常而不是xalloc异常

void my_new_handler()
{
	throw Noman();
}

new_handler Old_Handler_ = set_new_handler(my_new_handler);

class OutOfBounds
{
public:
	OutOfBounds()
	{
		cout << "超出范围" << endl;
	}
	~OutOfBounds()
	{

	}
};


为了超出数组触发不同的异常警告。

还是回到类成员函数中(listearLine.h 里面): 

构造函数与析构函数:

template
inline LinearList::LinearList()
{
	MaxSize = 1;
	element = new T[MaxSize];
	length = 0;
}

//构造函数默认为10
template
LinearList::LinearList(int MaxListSize)
{
	MaxSize = MaxListSize;
	element = new T[MaxSize];
	length = 0;
}

//析构函数
template
LinearList::~LinearList()
{
	delete[] element;  
}

是否为空:

//判断是否为空
template
bool LinearList::IsEmpty() const
{
	return 0 == length;
}

Find函数:

//返回第k个元素至x中 若不存在第k个元素,则返回false
template
bool LinearList::Find(int k, T & x) const
{
	if (k<1 || k>length)
	{
		return false;
	}
	else
	{
		x = element[k-1];
	}

	return true;
}

查找函数:

template
int LinearList::Search(const T & x) const
{
	for (int i =0; i

删除数据:

template
LinearList& LinearList::Delete(int k, T & x)
{

	if (Find(k,x))
	{
		for (int i = k; i < length; i++)
		{
			element[i - 1] = element[i];
		}
		length--;
		if (length == (MaxSize / 4) && length > 0)
		{
			MaxSize /= 2;
			changeSize(element,length,MaxSize);
		}
		
		return *this;
	}
	else
	{
		throw  OutOfBounds();
	}
}

这里本没有:

if (length == (MaxSize / 4) && length > 0)
		{
			MaxSize /= 2;
			changeSize(element,length,MaxSize);
		}

这段代码,这里是后面习题中添加的功能,后面又详细解答。

插入函数:

//插入数据
//在第k个元素之后插入x;函数返回修改后的线性表
template
LinearList& LinearList::Insert(int k, const T & x)
{
	//在第k个元素之后插入x;函数返回修改后的线性表
	//如果不存在第k个元素,则引发异常OutOfBound
	//如果表已经满,则引发异常NoMem
	if (k<0 || k > length)
	{
		throw OutOfBounds();
	}
	if (length == MaxSize)
	{
		throw Noman();
	}
	//向后移动一位 书中这里是减一 书写错误
	for (int i = length - 1; i >= k; i--)
	{
		element[i + 1] = element[i];
	}
	element[k] = x;
	length++;
	if (length == MaxSize)
	{
		MaxSize *= 2;
		changeSize(element, length, MaxSize);
	}

	return *this;
}

输出函数与重构 << 符号输出:

template
void LinearList::Output(ostream & out) const
{
	for (int i = 0; i < length; i++)
	{
		out << element[i] << " ";
	}
}

template
ostream & operator<<(ostream & out, const LinearList & x)
{
	x.Output(out);
	return out;
}

已上的函数功能都是书中的代码部分,下面的部分为书上 课后习题里面需要的。

题目部分函数:

changeSize函数:

//改变大小,节省空间
template
inline LinearList& LinearList::changeSize(T * elementNew, int nlength, int max)
{
	element = new T[max];
	for (int i = 0; i

       这个函数可以节省空间,可以看插入函数与删除函数,在执行删除操作期间,如果线性表的尺寸降至当前 MaxSize 的四分之一,则分配一个更小的、尺寸为 MaxSize / 2的数组,并将老数组中的数据复制到新数组中,最后将老数组删除。

题目2:

Reverse函数:

//数据反转函数
template
 LinearList& LinearList::Reverse()
{
	for (int i = 0; i< (length/2); i++)
	{
		T temp = element[i];
		element[i] = element[length-1-i];
		element[length - 1 - i] = temp;
	}
	return *this;

}

//就地反转函数利用对象
template
void ReverseEle(LinearList & data)
{
	data.Reverse();
}

这里是后面对比使用的函数。


 

 template
 LinearList& LinearList::Half()
 {
	 length = (length + 1) / 2;
	 //这里两种方案来写程序,也是剑指offer中的知识点  
	 //方法1
	 T *elementNew = new T[length+1];
	 for (int i = 0; i<=length; i++)
	 {
		 elementNew[i] = element[2 * i];
	 }
	 delete[] element;

	 element = new T[length+1];
	 for (int i = 0; i <= length; i++)
	 {
		 element[i] = elementNew[i];
	 }

	 delete[] elementNew;
	 return *this;
	 //方法二是直接利用构造函数,这样就不用自己写delete了,这里就不记录了
 }

(1小时数据结构)数据结构c++版本(一)--- 线性表数组表达_第3张图片

 复制构造函数:

//复制构造函数
template
 LinearList::LinearList(const LinearList& L)
{
	if (this == &L)
	{
		return;
	}
	else
	{
		this->length = L.length;
		this->MaxSize = L.MaxSize;
		delete[] element;
		element = new T[length+1];
		memcpy(element, L.element, length * sizeof(T));

	}
}

当写完后一定要写重载 = 符号不然很容易出问题:

template
inline LinearList& LinearList::operator=(const LinearList& x)
{
	if (this == &x)
	{
		return *this;
	}
	this->MaxSize = x.MaxSize;
	this->length = x.length;
	memcpy(element, x.element,length * sizeof(T));
}

(1小时数据结构)数据结构c++版本(一)--- 线性表数组表达_第4张图片

操作函数:

template
 bool LinearList::Current(T & x)
 {
	 if (current < 0 || current > MaxSize)
	 {
		 return false;
	 }
	 else
	 {
		 x = element[current - 1];
		 return true;
	 }

 }

 template
 inline bool LinearList::End() const
 {
	 return current == length;
 }

 template
 inline bool LinearList::Front() const
 {
	 return current == 1;
 }

 template
 inline void LinearList::Next()
 {
	 if (current < length)
	 {
		 current++;
	 }
	 else
	 {
		 throw OutOfBounds();
	 }
 }

 template
 inline void LinearList::Previous()
 {
	 if (current > 1)
	 {
		 current--;
	 }
	 else
	 {
		 throw OutOfBounds();
	 }
 }

 template
  void LinearList::clear()
 {
	  this->MaxSize = 1;
	  delete [] element;
	  element = new T[MaxSize];
	  this->length = 0;
 }

Reset 在定义的时候已经写完了。这里我自己添加了个clear函数。

(1小时数据结构)数据结构c++版本(一)--- 线性表数组表达_第5张图片

线性交叉函数:

template
 LinearList& LinearList::Alternate(const LinearList& list1, const LinearList& list2)
 {
	 //线性交叉 
	 if (length>0)
	 {
		 delete[] element; //清除原有数据
	 }
	 length = list1.length + list2.length;
	 element = new T[length]; 
//	 MaxSize = length;
	 LinearList A = list1, B = list2; //复制构造函数
	 A.Reset();
	 B.Reset();
	 int value = 0; //记录当前位置的值
	 int minLenght = A.length <= B.length ? A.length: B.length; //获取当前比较小的值

	 for (int i = 0; i

 Merge函数:

template
 LinearList& LinearList::Merge(const LinearList& list1, const LinearList& list2)
 { 
	 if (length > 0)
	 {
		 delete[] element;
	 }
	 length = list1.length + list2.length;
	 MaxSize = length;
	 element = new T[length]; //创建新的标签

	 int ca = 0, cb = 0, ct = 0;
	 //先拍都有的数据
	 while (ca < list1.length && cb < list2.length)
	 {
		 if (list1.element[ca] >= list2.element[cb])
		 {
			 element[ct++] = list2.element[cb++];
		 }
		 else
			 element[ct++] = list1.element[ca++];
	 }
	 //在排剩下的数据
	 if (ca == list1.length) //表示list1数组排完了
	 {
		 for (int i = cb;i < list2.length;i++)
		 {
			 element[ct] = list2.element[i];
			 ct++;
		 }
	 }
	 else
	 {
		 for (int i = ca; i < list1.length; i++)
		 {
			 element[ct] = list1.element[i];
			 ct++;
		 }
	 }
	 return *this;
 }

Split函数:

 void LinearList::Split(LinearList& list1, LinearList& list2)
 {
	 int aNum = 0;
	 int bNum = 0;
	 for (int i = 0; i < length; i++)
	 {
		 if ((i & 1) == 0)
		 {
			 list1.Insert(aNum++, element[i]);
		 }
		 else
		 {
			 list2.Insert(bNum++, element[i]);
		 }
	 }
 }

   测试程序:

//测试列表数组
void testLinearList()
{
	try
	{
		//设置为空的时候
		cout << "初始化开始" << endl;
		LinearList L;
		cout << "Lenght = " << L.Length() << endl;
		cout << "IsEmpty = " << L.IsEmpty() << endl;

		L.Insert(0, 2);
		L.Insert(1, 6);
		//也可以这样写
		L.Insert(2, 5).Insert(3, 4).Insert(4, 8);
		cout << "List is " << L << endl;
		cout << "isEmpty " << L.IsEmpty() << endl;

		//测试插入函数
		L.Insert(1, 10).Insert(2,1);
		cout << "List is " << L << endl;
		cout << "isEmpty " << L.IsEmpty() << endl;
		cout << "lengh is " << L.Length()<< endl;
		int z;
		L.Find(1, z); //找到第一个数的数据
		cout << "first element " << z << endl;
		cout << "Lenght = " << L.Length() << endl;
		cout << "lengh is " << L.Length() << endl;

		L.Delete(1, z);
		cout << "Deleted element is " << z << endl;
		cout << "List is " << L << endl;
		cout << "lengh is " << L.Length() << endl;

		cout << endl;
		//测试查找
		cout << "test Search" << endl;
		cout << "List is " << L << endl;
		cout << "6 in L? " << L.Search(6) << endl;
		cout << "9 in L? " << L.Search(9) << endl;

		cout << endl;
		cout << "test Reverse" << endl;
		L.Reverse();
		cout << "List is " << L << endl;
		cout << "isEmpty " << L.IsEmpty() << endl;
		cout << "lengh is " << L.Length() << endl;
		
		//反转测试
		for (int i = 0; i<500000; i++)
		{
			L.Insert(i, i);
		}
		cout << L.Length() << endl;
		clock_t  startTime, stopTime;
		startTime = clock();
		L.Reverse();
		stopTime = clock();

		cout << "类成员反转使用的时间: " << float(stopTime - startTime) / CLK_TCK << endl;

		//就地反转
		startTime = clock();
		ReverseEle(L);
		stopTime = clock();
		cout << "就地反转使用的时间: " << float(stopTime - startTime) / CLK_TCK << endl;

		//测试half
		L.Half();
		cout << "length is : " << L.Length()<< endl;

		//测试复制构造函数
		LinearList ML(L);
		cout << "length L is : " << L.Length() << endl;
		cout << "length ML is : " << ML.Length() << endl;

		//测试current类容
		ML.Reset(); //位置置0

		//测试next
		ML.Next(); //移动到下个位置
		cout << "判断是否是前边的 " << ML.Front() << endl;
		int value = 0;
		cout << "当前是否有问题 :" << ML.Current(value) << endl;
		cout << "输出当前的值是 :" << value << endl;
		//其他函数测试也是相同的

		//测试交叉数据
		LinearList A, B;
		for (int i = 0; i<4; i++)
		{
			A.Insert(i, i);
			B.Insert(i, i);
		}
		B.Insert(4, 4).Insert(5, 5);
		cout << "A is List : " << A < C;
		C.Alternate(A,B);
		cout << "C is list :" << C << endl;
		//测试合并排序,前提都是顺序的
		A.Insert(4, 10);
		LinearList D;
		D.Merge(A,B);
		cout << "D is list :" << D << endl;

		//测试
		A.clear();
		B.clear();
		D.Split(A,B);
		cout << "D is list :" << D << endl;
		cout << "A is List : " << A << endl;
		cout << "B is List : " << B << endl;


	}
	catch (const std::exception&)
	{
		cerr << "An exception has occurred" << endl;
	}
}

 主函数:

#include 
#include "listearLine.h"
using namespace std;

int main()
{
	//测试线性表数组
	testLinearList();
	return 0;
}

      已上就是题目中的程序了,从第9题目开始,只是变成下标为1开始数组,这里类推一下就好不难的。写题目部分程序毕竟是自己来写的,难免会有程序问题,若你有发现问题,可在下面评论区交流,或者关注我博客,让我们一起进步,加油。

需要书籍的可以来取:

         对应数据结构的书籍

本文例子的连接:

 链接:本文例子  提取码:ao3c

如果例子失效,可以私信,或者下方评论。

你可能感兴趣的:(数据结构与算法,线性表,数组,c++,数据结构与算法c++描述)