【数据结构】02线性表-顺序表

1. 定义

线性表(List):零个或多个具有相同特性的数据元素的有限序列

  • 若将线性表记为 L = ( a 1 , . . . , a i − 1 , a i , a i + 1 , . . . , a n ) L=(a_1,...,a_{i-1},a_{i},a_{i+1},...,a_n) L=(a1,...,ai1,ai,ai+1,...,an),则称 a i − 1 a_{i-1} ai1 a i a_{i} ai直接前驱元素, a i + 1 a_{i+1} ai+1 a i a_{i} ai直接后继元素
  • 线性表的元素个数 n ( n ≥ 0 ) n(n\ge0) n(n0)定义为线性表的长度,当 n = 0 n=0 n=0时,称为空表
  • 在非空表中的每个数据元素都有一个确定的位置,如 a 1 a_1 a1是第一个元素, a n a_n an是最后一个元素, a i a_i ai是第 i i i个元素,称 i i i为数据元素 a i a_i ai在线性表中的位序

2. 线性表的顺序存储结构

线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素,简称顺序表。
顺序表的静态实现:采用数组,表初始化后不能扩展存储空间
顺序表的动态实现:采用动态分配内存,表可以任意扩展存储空间
顺序表的优点是随机访问很快,通过数组下标或指针的运算,时间复杂度为 O ( 1 ) O(1) O(1),但是插入和删除数据的时候,需要移动元素,内存拷贝次数较多

2.1 顺序表的静态实现

#define MAXSIZE 100// 存储空间初始分配量
typedef int ElemType; // 定义顺序表的数据元素为整数
classSqList
{
private:
	ElemType data[MAXSIZE]; // 数组,存储数据元素
	int length;// 线性表当前长度即元素个数
};

描述顺序存储结构需要三个属性:

  • 存储空间的起始位置:数组data,它的存储位置就是存储空间的存储位置
  • 线性表的最大容量:数组长度,MAXSIZE
  • 线性表的当前长度(数组元素个数):length

数组长度是存放是线性表的存储空间长度,线性表的长度是线性表中的数据元素个数。在任意时刻,线性表长度小于等于数组长度。

2.1.1 获取元素操作

获取操作思路:

  • 线性表为空,或位置不正确(不在1到length之间),抛出异常
  • 利用指针返回第i个位置的元素,即下标i-1
	/// <summary>
	/// 获取表中第i个位置元素的值,存放到ee中
	/// </summary>
	/// <param name="i">待获取元素的位置</param>
	/// <param name="ee">返回元素值</param>
	/// <returns>false失败/true成功</returns>
	bool GetElem(int i, Elemtype* ee)const
	{
		if (length==0||i<1||i>length)// 表为空,位置非法
		{
			return false;
		}
		memcpy(ee, &data[i - 1], sizeof(Elemtype)); 
		return true;
	}

2.1.2 插入操作

插入算法思路:

  • 插入位置不合理,抛出异常
  • 线性表长度大于数组长度,则抛出异常或动态增加容量
  • 从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置
  • 将要插入的元素填入位置i处
  • 表长加一
	/// <summary>
	/// 在顺序表第i个位置插入元素ee
	/// </summary>
	/// <param name="i">位置</param>
	/// <param name="ee">待插入元素</param>
	/// <returns>false失败/true成功</returns>
	bool ListInsert(int i, Elemtype* ee)
	{
		if (ee == nullptr || length == MAXSIZE)//待插入元素为空,或表满
		{
			return false;
		}
		if (i<1||i>length+1)// 比第一个元素位置小,比最后一个元素位置大
		{
			return false;
		}
	    // 将第i个位置之后的元素向后移动一位
		for (int k = length; k >=i; k--)
		{
			memcpy(&data[k], &data[k-1], sizeof(Elemtype)); // k-1 -> k
		}
		// 插入元素
		memcpy(&data[i-1], ee, sizeof(Elemtype));
		// 维护长度
		length++;
	}

2.1.3 删除操作

删除操作思路:

  • 当线性表为空,删除位置不正确(不在1到length之间),抛出异常
  • 取出删除元素
  • 删除元素后面的元素向前移动一位
  • 表长度减一
	/// <summary>
	///  删除顺序表第i个位置的元素,并通过ee返回删除的元素
	/// </summary>
	/// <param name="i">待删除元素位置</param>
	/// <param name="ee">删除元素的值</param>
	/// <returns>false失败/true成功</returns>
	bool ListDelete(int i,Elemtype* ee)
	{
		if (length==0||i<1||i>length)// 表为空,或待删除的位置不正确
		{
			ee = nullptr;
			return false;
		}
		// 返回删除的元素
		memcpy(ee, &data[i - 1], sizeof(Elemtype));
		// 把i后面的元素前移一位
		for (int k = i; k <= length; k++)
		{
			memcpy(&data[k - 1], &data[k], sizeof(Elemtype)); // k->k-1
		}
		length--;
		return true;
	}

2.1.4 完整实现

#include <iostream>
using namespace std;

#define MAXSIZE 100
typedef int Elemtype;

class SqList
{
public:
	SqList()
	{
		ClearList();
	};
	~SqList()
	{
		ClearList();
	}

	/// <summary>
	/// 在顺序表第i个位置插入元素ee
	/// </summary>
	/// <param name="i">位置</param>
	/// <param name="ee">待插入元素</param>
	/// <returns>false失败/true成功</returns>
	bool ListInsert(int i, Elemtype* ee)
	{
		if (ee == nullptr || length == MAXSIZE)//待插入元素为空,或表满
		{
			return false;
		}
		if (i<1||i>length+1)// 比第一个元素位置小,比最后一个元素位置大
		{
			return false;
		}
	    // 将第i个位置之后的元素向后移动一位
		for (int k = length; k >=i; k--)
		{
			memcpy(&data[k], &data[k-1], sizeof(Elemtype)); // k-1 -> k
		}
		// 插入元素
		memcpy(&data[i-1], ee, sizeof(Elemtype));
		// 维护长度
		length++;
	}

	/// <summary>
	///  删除顺序表第i个位置的元素,并通过ee返回删除的元素
	/// </summary>
	/// <param name="i">待删除元素位置</param>
	/// <param name="ee">删除元素的值</param>
	/// <returns>false失败/true成功</returns>
	bool ListDelete(int i,Elemtype* ee)
	{
		if (length==0||i<1||i>length)// 表为空,或待删除的位置不正确
		{
			ee = nullptr;
			return false;
		}
		// 返回删除的元素
		memcpy(ee, &data[i - 1], sizeof(Elemtype));
		// 把i后面的元素前移一位
		for (int k = i; k <= length; k++)
		{
			memcpy(&data[k - 1], &data[k], sizeof(Elemtype)); // k->k-1
		}
		length--;
		return true;
	}

	/// <summary>
	/// 获取表中第i个位置元素的值,存放到ee中
	/// </summary>
	/// <param name="i">待获取元素的位置</param>
	/// <param name="ee">返回元素值</param>
	/// <returns>false失败/true成功</returns>
	bool GetElem(int i, Elemtype* ee)const
	{
		if (length==0||i<1||i>length)// 表为空,位置非法
		{
			return false;
		}
		memcpy(ee, &data[i - 1], sizeof(Elemtype)); 
		return true;
	}

	/// <summary>
	/// 定位元素
	/// </summary>
	/// <param name="ee">待定位的元素</param>
	/// <returns>-1失败/位序</returns>
	int LocateElem(Elemtype* ee)const
	{
		if (length==0) //表为空
		{
			return -1;
		}
		for (int i = 0; i < length; i++)
		{
			if (data[i] == *ee)
			{
				return i + 1;
			}
		}
		// 未找到
		return -1;
	}
	/// <summary>
	/// 删除表头元素
	/// </summary>
	/// <param name="ee">接收表头元素</param>
	/// <returns></returns>
	bool ListPopFront(Elemtype* ee)
	{
		return ListDelete(1, ee);
	}

	/// <summary>
	/// 删除表尾元素
	/// </summary>
	/// <param name="ee">接收表尾元素</param>
	/// <returns></returns>
	bool ListPopBack(Elemtype* ee)
	{
		return ListDelete(length, ee);
	}

	bool IsEmpty(void)const
	{
		return length == 0;
	}

	void ClearList(void)
	{
		this->length = 0; //表长置为0
		memset(this->data, 0, sizeof(Elemtype) * MAXSIZE); 
	}

	void ListShow(void)const
	{
		if (length == 0)
		{
			cout << "表为空" << endl;
		}
		for (int i = 0; i < length; i++)
		{
			cout << data[i] << " ";
		}
		cout << endl;
	}

private:
	int length;
	int data[MAXSIZE];
};


int main(void)
{
	// 创建顺序表
	SqList LL;

	// 创建数据元素
	Elemtype ee;

	ee = 1; LL.ListInsert(1, &ee);
	ee = 2; LL.ListInsert(1, &ee);
	ee = 3; LL.ListInsert(1, &ee);
	ee = 4; LL.ListInsert(1, &ee);
	ee = 5; LL.ListInsert(1, &ee);

	cout << "初始" << endl;
	LL.ListShow();
	cout << "删除表头" << endl;
	LL.ListPopFront(&ee);
	cout << ee << endl;
	LL.ListShow();

	cout << "删除表尾" << endl;
	LL.ListPopBack(&ee);
	cout << ee << endl;
	LL.ListShow();

	cout << "获取元素" << endl;
	LL.GetElem(1, &ee);
	cout << ee << endl;

	cout << "定位元素" << endl;
	ee = 3;
	cout << ee << "在" << LL.LocateElem(&ee) << endl;

	return 0;
}

2.2 顺序表的动态实现

顺序表的动态实现采用动态内存分配的方法,当表中的元素达到最大时可以自动扩展
具体的代码实现

#include <iostream>
using namespace std;

#define INITSIZE 10 // 顺序表初始长度
#define EXTSIZE 5   // 每次扩展元素的个数

typedef int ElemType;

class SqList
{
public:
	SqList()
	{
		data = new ElemType[INITSIZE];

		length = 0;
		maxsize = INITSIZE;
		memset(data, 0, sizeof(ElemType) * maxsize);
	};

	~SqList()
	{
		length = 0;
		memset(data, 0, sizeof(ElemType) * maxsize);
		maxsize = 0;
		delete[] data;
	};

	/// <summary>
	/// 向表中第i个位置插入元素ee
	/// </summary>
	/// <param name="i">插入位序</param>
	/// <param name="ee">待插入元素</param>
	/// <returns>false失败/true成功</returns>
	bool ListInsert(int i, ElemType* ee)
	{
		if (ee==nullptr||i<1||i>maxsize+1)//待插入元素为空,或插入位置不对
		{
			return false;
		}
		// 判断是否需要增加容量
		if (length == maxsize)
		{
			if (ListExtend()==false)
			{
				cout << "申请内存失败" << endl;
				return false;
			}
		}
		// 从第i个位置开始往后的元素向后移动一位
		for (int k = length; k >=i; k--)
		{
			memcpy(&data[k], &data[k - 1], sizeof(ElemType)); //k-1 -> k
		}
		// 插入元素
		memcpy(&data[i - 1], ee, sizeof(ElemType));
		// 增加长度
		length++;
	}

	/// <summary>
	/// 删除位序为i的元素
	/// </summary>
	/// <param name="i">待删除位序i</param>
	/// <param name="ee">接收删除的元素</param>
	/// <returns>false失败/true成功</returns>
	bool ListDelete(int i, ElemType* ee)
	{
		if (length == 0 || i<1 || i>length)   // 表为空,或删除位置不正确 
		{
			return false;
		}
		// 返回删除的元素
		memcpy(ee, &data[i - 1], sizeof(ElemType));
		// 把i后面的元素向前移动一位
		for (int k = i; k < length; k++)
		{
			memcpy(&data[k - 1], &data[k], sizeof(ElemType));// k->k-1
		}
		// 长度--
		length--;
		return true;
	}

	bool GetElem(int i, ElemType* ee)const
	{
		if (length == 0 || i<1 || i>length)
		{
			return false;
		}
		memcpy(ee, &data[i - 1], sizeof(ElemType));
		return true;
	}


	/// <summary>
	/// 定位元素
	/// </summary>
	/// <param name="ee">待定位的元素</param>
	/// <returns>-1失败/位序</returns>
	int LocateElem(ElemType* ee)const
	{
		if (length == 0) //表为空
		{
			return -1;
		}
		for (int i = 0; i < length; i++)
		{
			if (data[i] == *ee)
			{
				return i + 1;
			}
		}
		// 未找到
		return -1;
	}

	/// <summary>
	/// 删除表头元素
	/// </summary>
	/// <param name="ee">接收表头元素</param>
	/// <returns></returns>
	bool ListPopFront(ElemType* ee)
	{
		return ListDelete(1, ee);
	}

	/// <summary>
	/// 删除表尾元素
	/// </summary>
	/// <param name="ee">接收表尾元素</param>
	/// <returns></returns>
	bool ListPopBack(ElemType* ee)
	{
		return ListDelete(length, ee);
	}

	bool IsEmpty(void)const
	{
		return length == 0;
	}

	void ClearList(void)
	{
		length = 0;
		maxsize = INITSIZE;
		memset(data, 0, sizeof(ElemType) * maxsize);
	}

	void ListShow(void)const
	{
		if (length == 0)
		{
			cout << "表为空" << endl;
		}
		for (int i = 0; i < length; i++)
		{
			cout << data[i] << " ";
		}
		cout << endl;
	}
private:
	ElemType* data;
	int maxsize; // 顺序表元素的最大个数
	int length; // 当前元素个数

	/// <summary>
	/// 扩展内存空间
	/// </summary>
	/// <returns>false失败/true成功</returns>
	bool ListExtend()
	{
		// 申请内存空间
		ElemType* newdata = new(std::nothrow) ElemType[maxsize + EXTSIZE];

		if (newdata == nullptr)
		{
			return false;
		}
		// 先初始化内存
		memset(newdata, 0, sizeof(ElemType) * (maxsize + EXTSIZE));
		// 拷贝内容
		memcpy(newdata, data, sizeof(ElemType) * maxsize);
		// 删除原始内容
		delete[] data;

		// 重新分配指针
		data = newdata;
		maxsize = maxsize + EXTSIZE;
		return true;
	}
};

int main(void)
{
	SqList LL;
	ElemType ee;

	ee = 1; LL.ListInsert(1, &ee);
	ee = 2; LL.ListInsert(2, &ee);
	ee = 3; LL.ListInsert(3, &ee);
	ee = 4; LL.ListInsert(4, &ee);
	ee = 5; LL.ListInsert(5, &ee);
	ee = 6; LL.ListInsert(6, &ee);
	ee = 7; LL.ListInsert(7, &ee);
	ee = 8; LL.ListInsert(8, &ee);
	ee = 9; LL.ListInsert(9, &ee);
	ee = 10; LL.ListInsert(10, &ee);
	ee = 11; LL.ListInsert(11, &ee);
	
	cout << "初始" << endl;
	LL.ListShow();
	cout << "删除表头" << endl;
	LL.ListPopFront(&ee);
	cout << ee << endl;
	LL.ListShow();

	cout << "删除表尾" << endl;
	LL.ListPopBack(&ee);
	cout << ee << endl;
	LL.ListShow();

	cout << "获取元素" << endl;
	LL.GetElem(1, &ee);
	cout << ee << endl;

	cout << "定位元素" << endl;
	ee = 3;
	cout << ee << "在" << LL.LocateElem(&ee) << endl;

	return 0;
}

2.3 优缺点

  • 优点:
    • 无须为表中元素的逻辑关系增加额外的存储空间
    • 可以快速地存取表中任意位置的元素
  • 缺点:
    • 插入和删除操作需要移动大量元素
    • 线性表长度变化较大时,难以确定存储空间的容量
    • 造成存储空间的“碎片”

3. 顺序表的合并

现有两张升序排序的顺序表La和Lb,现在需要将他们按照元素大小升序合并成新的顺序表Lc
比较两张表首的元素大小,弹出较小的表中元素,插入到表Lc中。直到某个表为空。然后将不为空的表剩余元素直接合并到Lc中。
采用动态实现的顺序表实现的代码如下

#include <iostream>
using namespace std;

#define INITSIZE 10 // 顺序表初始长度
#define EXTSIZE 5   // 每次扩展元素的个数

// 将两个升序的顺序表La和Lb,合并成一个升序的顺序表Lc

typedef int ElemType;

class SqList
{
public:
	SqList()
	{
		data = new ElemType[INITSIZE];

		length = 0;
		maxsize = INITSIZE;
		memset(data, 0, sizeof(ElemType) * maxsize);
	};

	SqList(SqList& L) // 拷贝构造函数
	{
		data = new ElemType[INITSIZE];

		length = 0;
		maxsize = INITSIZE;
		memset(data, 0, sizeof(ElemType) * maxsize);
		
		for (int i = 0; i < L.length; i++)
		{
			this->ListInsert(i + 1, &L.data[i]);// 拷贝数据
		}
	}

	~SqList()
	{
		length = 0;
		memset(data, 0, sizeof(ElemType) * maxsize);
		maxsize = 0;
		delete[] data;
	};

	/// <summary>
	/// 向表中第i个位置插入元素ee
	/// </summary>
	/// <param name="i">插入位序</param>
	/// <param name="ee">待插入元素</param>
	/// <returns>false失败/true成功</returns>
	bool ListInsert(int i, ElemType* ee)
	{
		if (ee == nullptr || i<1 || i>maxsize + 1)//待插入元素为空,或插入位置不对
		{
			return false;
		}
		// 判断是否需要增加容量
		if (length == maxsize)
		{
			if (ListExtend() == false)
			{
				cout << "申请内存失败" << endl;
				return false;
			}
		}
		// 从第i个位置开始往后的元素向后移动一位
		for (int k = length; k >= i; k--)
		{
			memcpy(&data[k], &data[k - 1], sizeof(ElemType)); //k-1 -> k
		}
		// 插入元素
		memcpy(&data[i - 1], ee, sizeof(ElemType));
		// 增加长度
		length++;
	}

	/// <summary>
	/// 删除位序为i的元素
	/// </summary>
	/// <param name="i">待删除位序i</param>
	/// <param name="ee">接收删除的元素</param>
	/// <returns>false失败/true成功</returns>
	bool ListDelete(int i, ElemType* ee)
	{
		if (length == 0 || i<1 || i>length)   // 表为空,或删除位置不正确 
		{
			return false;
		}
		// 返回删除的元素
		memcpy(ee, &data[i - 1], sizeof(ElemType));
		// 把i后面的元素向前移动一位
		for (int k = i; k < length; k++)
		{
			memcpy(&data[k - 1], &data[k], sizeof(ElemType));// k->k-1
		}
		// 长度--
		length--;
		return true;
	}

	bool GetElem(int i, ElemType* ee)const
	{
		if (length == 0 || i<1 || i>length)
		{
			return false;
		}
		memcpy(ee, &data[i - 1], sizeof(ElemType));
		return true;
	}


	/// <summary>
	/// 定位元素
	/// </summary>
	/// <param name="ee">待定位的元素</param>
	/// <returns>-1失败/位序</returns>
	int LocateElem(ElemType* ee)const
	{
		if (length == 0) //表为空
		{
			return -1;
		}
		for (int i = 0; i < length; i++)
		{
			if (data[i] == *ee)
			{
				return i + 1;
			}
		}
		// 未找到
		return -1;
	}

	/// <summary>
	/// 删除表头元素
	/// </summary>
	/// <param name="ee">接收表头元素</param>
	/// <returns></returns>
	bool ListPopFront(ElemType* ee)
	{
		return ListDelete(1, ee);
	}

	/// <summary>
	/// 删除表尾元素
	/// </summary>
	/// <param name="ee">接收表尾元素</param>
	/// <returns></returns>
	bool ListPopBack(ElemType* ee)
	{
		return ListDelete(length, ee);
	}

	bool IsEmpty(void)const
	{
		return length == 0;
	}

	void ClearList(void)
	{
		length = 0;
		maxsize = INITSIZE;
		memset(data, 0, sizeof(ElemType) * maxsize);
	}

	void ListShow(void)const
	{
		if (length == 0)
		{
			cout << "表为空" << endl;
		}
		for (int i = 0; i < length; i++)
		{
			cout << data[i] << " ";
		}
		cout << endl;
	}

	SqList& ListMerge(SqList& La)
	{
		if (La.length == 0)// 如果待合并的表为空
		{
			return *this; // 返回自身
		}
		// 创建自身的临时拷贝
		SqList Lb = *this;
	
		// 把La和Lb合并到this
		int is_start_la = 0;
		int is_start_lb = 0;
		int is_start_lc = 0;

		this->ClearList();


		while (is_start_la < La.length && is_start_lb < Lb.length)
		{
			this->ListInsert
			(++is_start_lc,
				La.data[is_start_la] < Lb.data[is_start_lb] ?
				&La.data[is_start_la++] : &Lb.data[is_start_lb++]
			);
		}
		// 把La其他内容追加到this
		while (is_start_la < La.length)
		{
			this->ListInsert(++is_start_lc, &La.data[is_start_la++]);
		}

		// 把Lb其他内容追加到this
		while (is_start_lb < Lb.length)
		{
			this->ListInsert(++is_start_lc, &Lb.data[is_start_lb++]);
		}
		return *this;
	};


private:
	ElemType* data;
	int maxsize; // 顺序表元素的最大个数
	int length; // 当前元素个数

	/// <summary>
	/// 扩展内存空间
	/// </summary>
	/// <returns>false失败/true成功</returns>
	bool ListExtend()
	{
		// 申请内存空间
		ElemType* newdata = new(std::nothrow) ElemType[maxsize + EXTSIZE];

		if (newdata == nullptr)
		{
			return false;
		}
		// 先初始化内存
		memset(newdata, 0, sizeof(ElemType) * (maxsize + EXTSIZE));
		// 拷贝内容
		memcpy(newdata, data, sizeof(ElemType) * maxsize);
		// 删除原始内容
		delete[] data;

		// 重新分配指针
		data = newdata;
		maxsize = maxsize + EXTSIZE;
		return true;
	}
};

int main(void)
{
	SqList L1,L2;
	ElemType ee;

	ee = 1; L1.ListInsert(1, &ee);
	ee = 3; L1.ListInsert(2, &ee);
	ee = 6; L1.ListInsert(3, &ee);
	ee = 8; L1.ListInsert(4, &ee);
	ee = 10; L1.ListInsert(5, &ee);
	ee = 11; L1.ListInsert(6, &ee);

	ee = 2; L2.ListInsert(1, &ee);
	ee = 4; L2.ListInsert(2, &ee);
	ee = 5; L2.ListInsert(3, &ee);
	ee = 7; L2.ListInsert(4, &ee);
	ee = 9; L2.ListInsert(5, &ee);
	L1.ListShow();
	L2.ListShow();

	L1 = L1.ListMerge(L2);
	L1.ListShow();

	SqList L3 = L1;

	L1 = L1.ListMerge(L3);
	L1.ListShow();

	return 0;
}

------------------------分隔线---------------------------
在学习了C++模板类之后,利用模板类实现了顺序表
具体实现如下

#include <iostream>
using namespace std;

#define INITSIZE 10
#define EXTENDSIZE 5

template<class T>
class SqList
{
public:
	SqList();
	SqList(const SqList<T>& L);
	~SqList()
	{
		delete[] data;
		length = 0;
		maxsize = 0;
	};

	/* 类成员函数*/
	void ListShow();
	SqList<T>& ListInsert(int i, const T& elem);
	SqList<T>& ListDelete(int i, T& elem);
	SqList<T>& ListPopFront(T& elem);
	SqList<T>& ListPopBack(T& elem);
	SqList<T>& ListPushBack(const T& elem);
	bool GetElem(int i, T& elem);
private:
	/*成员变量*/
	int maxsize; // 最大长度
	int length; // 当前元素个数
	T* data;//一维元素动态数组

	bool ListExtend();
};

template<class T>
SqList<T>::SqList()
{
	data = new T[INITSIZE]; // 分配内存
	length = 0;
	maxsize = INITSIZE;
};


template<class T>
SqList<T>::SqList(const SqList<T>& L) // 拷贝构造函数
{
	data = new T[L.maxsize]; // 申请内存
	memcpy(this->data, L.data, sizeof(T) * L.length); // 拷贝数据
	length = L.length;
	maxsize = L.maxsize;
}

// 在第i个元素之后插入elem
template<class T>
SqList<T>& SqList<T>::ListInsert(int i, const T& elem) 
{
	if (length == maxsize)//存储空间是否足够
	{
		ListExtend();
	}

	if (i<1 || i>length + 1)// 位置不合法
	{
		return *this; // 无法插入
	}
	// 把第i个元素往后的元素向后移动一位
	for (int k = length; k >= i; k--)
	{
		memcpy(&data[k], &data[k - 1], sizeof(T)); // k-1 -> k
	}
	// 插入元素
	memcpy(&data[i-1], &elem, sizeof(T)); 

	length++;
	return *this;
}

//删除第i个元素,并通过elem返回
template<class T>
SqList<T>& SqList<T>::ListDelete(int i, T& elem)
{
	if (length == 0 || i<1 || i>length + 1) // 表为空,位置不合法
	{
		return *this; 
	}
	// 返回删除的元素
	memcpy(&elem, &data[i - 1], sizeof(T));

	// 把第i个元素往后的元素向前移动一位
	for (int k = i; k <= length; k++)
	{
		memcpy(&data[k-1], &data[k], sizeof(T)); // k -> k-1
	}

	length--;
	return *this;
}

// 弹出表头元素
template<class T>
SqList<T>& SqList<T>::ListPopFront(T& elem)
{
	return ListDelete(1, elem);
}

// 弹出表尾元素
template<class T>
SqList<T>& SqList<T>::ListPopBack(T& elem)
{
	return ListDelete(this->length + 1, elem);
}

// 获取第i个位置的元素
template<class T>
bool SqList<T>::GetElem(int i, T& elem)
{
	if (length == 0 || i<1 || i>length)// 表为空,位置非法
	{
		return false;
	}
	memcpy(&elem, &data[i - 1], sizeof(T));
	return true;
}

// 从末尾插入元素
template<class T>
SqList<T>& SqList<T>::ListPushBack(const T& elem)
{
	return ListInsert(this->length + 1, elem);
}

// 显示顺序表内容
template<class T>
void SqList<T>::ListShow()
{
	if (length == 0)
	{
		cout << "表为空" << endl;
		return;
	}
	for (int i = 0; i < length; i++)
	{
		cout << data[i] << " ";
	}
	cout << endl;
}

// 扩展内存
template<class T>
bool SqList<T>::ListExtend()
{
	// 申请内存空间
	T* newdata = new T[maxsize + EXTENDSIZE];
	if (newdata == nullptr)
	{
		return false;
	}
	// 先初始化内存
	memset(newdata, 0, sizeof(T) * (maxsize + EXTENDSIZE));
	// 拷贝原始数据
	memcpy(newdata, data, sizeof(T) * maxsize);
	// 释放原始数据内存
	delete[] data;
	// 指向新数据
	data = newdata;
	// 更新大小
	maxsize += EXTENDSIZE;
	return true;
}

int main(void)
{
	SqList<double> L;
	L.ListPushBack(1);
	L.ListPushBack(2);
	L.ListPushBack(3);
	L.ListPushBack(4);
	L.ListPushBack(5);
	L.ListPushBack(6);
	L.ListPushBack(7);
	L.ListPushBack(8);
	L.ListPushBack(9);
	L.ListPushBack(10);
	L.ListPushBack(11);
	L.ListShow();
	SqList<double>L2(L);
	L2.ListShow();
	double ee;
	L2.GetElem(3, ee);
	cout << ee << endl;
	
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值