数据结构——顺序表的整体实现(C++代码+详细注解)

代码如下:

PS:代码段的解释都用注释形式给出

#include<iostream>
using namespace std;


#define MaxSize 20				// 宏定义 相当于将文中所有 MaxSize 全部替换成 20 ,MaxSize相当于一个占位符 
typedef int DataType;			//定义int类型的别名 DataType 
typedef struct List				// 这边设置了结构体 List 的别名为 SeqList 
{
	DataType data[MaxSize];		// 以int类型的别名(实际上就是int型) 定义了一个数组,容量为MaxSize(实际上是20 个int类型的空间) 
	int length;					// 在结构体中还定义了表长,方便描述顺序表 
}SeqList;

void InitList(SeqList *L)		// 这边是定义顺序表的函数定义,一般只需将length置为空,证明是空表即可,因为数组空间是可复写的 
{								// 即使原数组空间中 data[0] data[1]……还存有数据,但是在插入的时候是直接以 length 为参考覆盖写入的 
	L->length=0;
}

int Length_List(SeqList *L)		//  定义返回表的长度的函数 
{
	return L->length;			
}

DataType InsertList(SeqList *L, int &i, DataType &e)		// 定义插入元素的函数,参数中的 int &i 和 DataType &e  为C++中的引用,可以自行了解下,主要作用为直接调用原变量节省栈空间 
{	
	int j;									
	if(L->length == MaxSize) 								// 这里可以看出,插入时是以 length 为参考,并不涉及原数组data[0]等实际存储内容,是默认覆盖的 
	{cout<<"表满,无法插入。"<<endl; 						// 这边判断了表示表厂的 length 是否等于分配的最大空间 【这边数组分配的空间是固定的】 当然也可以用动态分配 比如 C++ 中的 
		return 0;											// malloc 和 new 可以从堆中分配空间,就不用局限于 MaxSize 的大小,只受到堆空间的限制 
	}
	
	if(i<1||i>L->length+1)
	{
		cout<<"插入位置错误,请重新输入。"<<endl; 			// 判断插入元素的位置 i 是否在范围内 
		return 0;
	}
	
	for(j=L->length-1; j>=i-1;j--)							// 如果表未满且插入位置正确,那么从表尾元素【即 data[length-1] 开始,依次向 data[i+1] 赋值】 这样相当于将 data[i] 的值赋值 
	{														// 给了 data[i+1], 即从要插入的 i 位置开始,元素都向后移动一位,为要插入进来的元素腾出空间覆盖写入。 
		L->data[j+1] = L->data[j];
	}
	L->data[i-1] = e;
	L->length++;											// 别忘了插入之后要将 length++ 这是进行表操作的重要指标 
	cout<<"\n";
	return 1;
}

int Search_index_List(SeqList *L, int &i)					// 按序号i查找 
{
	if(i<1||i>L->length)									// 这边是一样的判断 不再赘述 
	{
		cout<<"超出查询范围,请重新输入。"<<endl;
		return 0; 
	}
	else
	{
		cout<<"\n查询的第"<<i<<"个位置的值为: "<<L->data[i-1]<<"\n"<<endl;		// 想着人性化一点,没有只返回 i 对应的值 
		return 0;
	} 
}

int Search_value_List(SeqList *L, DataType &e)			// 按值 e 查找 
{	
	int j;
	while(j<=L->length && L->data[j-1] != e)			// “ && ” 符号为 C++中的逻辑判断符,即两边的两个条件 有一个为假,那么整条语句都为假==>【有假为假,全真则真】,对应的是 “|| ”符号,含义为【有真则真,全假为假】 
		j++;											// 判断当 计数变量 j 小于等于 length 并且 data[j-1] 的值不与要查找的 e 相等时,计数变量 j 自增 1 , 继续向下查找 
	if(L->data[j-1] == e)								// 如果跳出 while 循环,那么我们第一步判断是否是在表中找到了我们想要的 e , 如果是,则输出对应语句 
	{
		cout<<"值为"<<e<<"的元素在第"<<j<<"个位置。\n"<<endl;
		return 0;
	}
	else
	{
		cout<<"未能查询到值为"<<e<<"的元素,请检查后重新输入。"<<endl; 		// 如果没有查找到,即 计数变量 j 已经超出表长 length 的范围了,那么就是在表中没有找到 
		return 0;
	}
}

DataType Delete_index_List(SeqList *L, int i)					// 按序号删除
{	
	int j;
	if(L->length == 0) 											// 一样的判断,不再赘述 
	{
		cout<<"表为空,无元素可删除。"<<endl;
		return 0;
	}
	
	if(i<1||i>L->length)
	{
		cout<<"序号超出范围,请重新输入。";
		return 0;
	} 
	
	cout<<"序号为 "<<i<<"的元素: "<<L->data[i-1] <<"已删除"<<endl;		// 这边是因为我想输出被删除的元素的值,如果在 for 循环删除语句之后输出,那么对应的 data[i-1] 就是被删除后表中的第一个元素了 
	 																	// 就是被删除后表中的第一个元素了,显然不符合我们的想法								
	for(j=i-1; j<=L->length-1;j++)						// for 循环 将计数变量 j = [i-1]  即序号为 i 的元素在数组中的下标。 PS:数组中的下标实际意义为首地址的偏移量,首地址为第一个元素 
	{													// 所以第一个元素的偏移量为 0 ,即第一个元素的下标为 data[0]。 
		L->data[j] = L->data[j+1];						//  从序号为 j 的元素开始,将 data[j+1] 的元素赋值给 data[j] ,即从后向前依次覆盖前一个元素,是为表中的删除操作 
	}

	L->length--;								// 同样的,删除完别忘记将 length 减 1  
	return 1;	 
}

DataType Delete_value_List(SeqList *L, DataType &e)			// 按值删除
{	
	int i=0;
	if(L->length == 0) 
	{
		cout<<"表为空,无元素可删除。"<<endl;			// 同样的判断,不再赘述 
		return 0;
	}
	
	
	while(i<L->length && L->data[i] != e)				// 和按值查找是一样的操作 
	{
		i++;
	}
	

	if(L->data[i] == e)								// 找到值为 e 的下标 i 后,进行按序号删除同样的步骤 
	{
	cout<<"表中序号为 "<<i<<"的元素: "<<e<<"已删除"<<endl;
		for(;i<=L->length-1;i++)
	{
		L->data[i] = L->data[i+1];
	}
	L->length--;
	}
	
	else
	{
	cout<<"表中无元素为"<<e<<"的值,请检查后重新输入。"<<endl; 
	return 0;
	}
		
}

void Print_List(SeqList *L)								//  输出顺序表 
{	
											
	if(L->length == 0)
	{
		cout<<"表中无元素可输出。\n";
	}
	
	else
	{	
		int i;
		cout<<"表中元素为:" ;
		for(i=0; i<L->length; i++)					// 这边用了 for 循环来输出表中【表示为一维数组】 的元素 
		{
			cout<<L->data[i]<<" ";
		}
		cout<<"\n"<<endl;
	}
}


int main()
{	
	SeqList L;							// 要先定义一个 SeqList 类型的变量 L 
	int input;							// 这边是输入的选项接受变量 
	
		while(1)						// 用 while 永真循环 这样不会初始化完顺序表就退出哈哈哈 
	{									
		cout<<"********************\n";
		cout<<"菜单选项:"<<"\n"
			<<"1 初始化顺序表"<<"\n"
			<<"2 查看顺序表的长度"<<"\n"
			<<"3 插入元素"<<"\n"
			<<"4 查找元素"<<"\n"
			<<"5 删除元素"<<"\n"
			<<"6 输出顺序表"<<"\n"
			<<"0 退出"<<"\n\n"<<endl;
		cout<<"请输入选项: ";
		cin>>input;						// 这边接受输入的选项     【PS:本来还想用 cin.fail() 控制下错误输出,即我定义的是 int 型的变量 input 如果有人输入了字符型,该给他什么样的反馈  
										// 也要充分注意到程序的健壮性,但是好不容易改错调试搞了半天就懒得弄啦哈哈哈哈  有兴趣的可以试一下】 
		
			switch(input)				// switch 根据 input 的值执行相应的 case,记得每个 case 的最后一定要加 break 不然会从当前 case 开始依次向下执行,直到遇到 break 
			{	
				int i,sw_input;			// 由于有多级选项 所以定义了 i 和 switch 内的 input 
				DataType e;				// 这边是定义了值 e 
				case 1:
						InitList(&L);						// 这边要注意了,因为在函数定义时,参数列表给的类型是 SeqList *L 即指针类型,指针变量是地址,所以这边要取 L 的地址作为参数传入 
						cout<<"初始化成功\n"<<endl;
						break;
				case 2:
						cout<<"顺序表的长度为:	"<<Length_List(&L)<<"\n"<<endl;   // 为什么函数定义要用指针这么麻烦呢,因为函数内的结果如果想带出来要么通过返回值 要么通过传址,可是返回值 
						break;													  //  还要对应变量接收 比较麻烦,具体想了解的可以去查阅下“函数的返回值,传址、引用啥的巴拉巴拉的 网上好多 
				case 3:															  // 大佬的解答都很详细 
						cout<<"请输入插入的位置及元素:	";
						cin>>i>>e;
						if(cin.fail()) break;			// 这边就是我上面提到的 cin 的异常捕捉 
						InsertList(&L, i, e);
						break;
				case 4:
						cout<<"请选择:\n"
							<<"1 按序号查找"<<"\n"
							<<"2 按值查找\n"<<endl;
						cout<<"请输入选项:";
						cin>>sw_input;
						if(cin.fail()) break;
						switch(sw_input)					// 多级选项再用一次 switch 语句 
						{
							case 1:
									cout<<"请输入要查找的序号: ";
									cin>>i;
									if(cin.fail()) break;
									Search_index_List(&L, i);
									break;
							case 2:
									cout<<"请输入要查找的值: "; 
									cin>>e;
									if(cin.fail()) break;
									Search_value_List(&L, e);
									break;	
						}
						break;
				case 5:
						cout<<"请选择:\n"
							<<"1 按序号删除"<<"\n"
							<<"2 按值删除\n"<<endl;
						cout<<"请输入选项:";
						cin>>sw_input;
						if(cin.fail()) break;
						switch(sw_input)
						{
							case 1:
									cout<<"请输入要删除的序号: ";
									cin>>i;
									if(cin.fail()) break;
									Delete_index_List(&L, i); 
									break;
							case 2:
									cout<<"请输入要删除的值: "; 
									cin>>e;
									if(cin.fail()) break;
									Delete_value_List(&L, e);
									break;	
						}
						break;
				case 6:
						Print_List(&L);
						break;
				case 0:
						return 0;
				default: cout<<"ERROR!"<<endl;	    // default 是 switch 里面默认的错误捕捉,即如果 case 都对应不上,就执行 default 
			}
	}
}

第一篇CSDN博客
写于2019年12月4日14:58

使用c++实现顺序表:多文件编程,层次清晰,函数有注释 SeqList();//构造函数,存储的元素个数设为0 bool setLength(size_t length);//设置已经存储的元素个数 bool addElement(ElemType element);//把某个元素添加到顺序表末尾 bool addElement(ElemType element , size_t n);//插入一个元素,使其成为第n个元素,其余元素后移 bool delElement();//删除所有的元素 bool delElement(size_t n);//删除第n个元素 bool delElement(string elementDetailType,string elementDetail);//通过某个元素细节找到元素,把这个元素删除 bool replaceElement(ElemType element , size_t n);//使用一个元素,替换掉第n个元素 bool swapElement(size_t n1 , size_t n2);//把第n1个元素和第n2个元素交换 ElemType* getElement();//得到数组头的指针 ElemType* getElement(size_t n);//得到第n个元素的指针 size_t getLength();//得到存储的元素个数 size_t getMaxSize();//得到顺序表容量 bool showElementDetail();//输出所有的元素细节 bool showElementDetail(size_t n);//输出第n个元素的细节 bool showElementDetail(string elementDetailType,string elementDetail);//通过某个元素细节找到元素,输出元素所有细节 size_t findElement(string elementDetailType,string elementDetail);//通过某个元素细节找到元素位置 static int inputAInt(int min = 0,int max = 9,int defaultValue = -1);//从键盘读取,限制为一个min到max间的整数,非法情况返回defaultValue void startControlLoop();//打开控制界面 ~SeqList();//析构函数
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值