数据结构——线性表——基本操作及相应的算法题

首先来对顺序表的定义

struct SeqList{
	Elemtype *data;//Elemtype 为虚拟的代码数据类型
	int MaxSize,Size;
}; 

这里要说明一下,就是在对一个顺序表初始化的时候,最好还是选择动态分配数组,为的是以后便于扩容。

这里的基本操作我选择是顺序表的插入,删除,查找。

插入:

bool ListInsert(Seqlist &L,int i,Elemtype e)
{
	if(i<1 || i>L.length +1)//这里使用+1的原因是使用  如果这个数是在这个最尾部 则依然可以插入 
	return false;
	if(L.length >= MaxSize)
	return false;
	
	for(int j = L.Length;j>=i;j--)
		L.data[j] = L.data[j-1];
	data[i - 1] = e;
	L.length++;
	return true;
}

删除:

bool ListDelete(SeqList &L,int i,Elemtype &e)//这里所删除位置的选项是e 而这个e还应当是返回 所以使用引用
{
	if(i<1||i>L.Length)//为什么这里是不需要+1  无法删除一个最尾部的空的元素 
	return false;
	e = L.data[i-1];
	
	for(int j = i;j<L.Length;j++)
	L.data[j-1] = L.data[j];
	L.Length--;
	return true;
 } 

PS:我认为插入和删除的有一点麻烦的地方就是有点难确定数组元素移动的截止条件。这里我建议读者最好还是选择在纸上把截止时的具体代码写下来,从而确定。

查找(遍历):

int LocateElem(SeqList L,Elemtype e){
	int i =0;
	for(;i<L.Length;i++)
	 if(L.data[i] == e)
	 	return i+1;//返回的是位置 
	 	
	 	return 0; 
}

下面才是重点,开始介绍几个数据结构考研的基础题,读者可以认真看看,以后的一些难一些的算法是在这个基础上衍生的,线性表是基础

题一:从顺序表中删除其值在给定值S与T之间(包含S和T要求,S<T的所有元素),如果S或T不合理或顺序表为空,则显示出错信息并退出运行。

算法思想:从前向后扫描顺序表L,用K记录下元素值,在S到T之间元素的个数(初始时K等于0),对于当前扫描的元素其实不在S到T之间则前移K个位置,否则执行K++,由于这样每个元素不在S和T之间的元素仅移动一次,所以算法效率高。有些读者可能会想,我可以直接遍历呀,遇到目标元素之后直接调用删除函数就行,但是删除函数的算法的时间复杂度是O(n),如果每次都调用的话,那么这个代价有点大。

bool Del_s_t(Seqlist &L,Elemtype s,Elemtype t) 
{
	int i,k = 0;
	if(L.length == 0||s>=t)
	return false;
	for(i = 0;i<L.Length;i++)
		if(L.data[i]>=s&&L.data[i]<=t)
		k++;//记录需要往前移动的个数
		else
		L.data[i-k] = L.data[i]; 
		//for
	L.Length -= k;
	return true; 
}

题二:从有序顺序表中删除所有其值重复的元素,使表中所有的元素的值均不同。

算法思想:有点类似于双指针法。注意是有序顺序,表值相同的元素一定在连续的位置上,用类似于直接插入排序的思想初始时,将第一个元素视为非重复的有序表之后,依次判断后面的元素是否与前面非重复有序表的最后一个元素相同,若相同则继续向后判断,若不同,则插入到前面,非重复有序表的最后直至判断到表尾为止。  算法思想叙述会有点复杂,直接看代码。

bool Delete_Same(Seqlist &L)
{
	if(!L.Length)
	return false;
	
	int i,j;//就是这两个双指针   i用于存储第一个不相同的元素,j为工作指针
	for(i = 0,j = 1;i<L.Lenghth;j++)
	if(L.data[i]!=L.data[j])
	{
		i++;
		L.data[i] = L.data[j];//不相同就替换   如果相同就工作指针后移。 
	 } 
	 L.Length = i+1;
	 return true;
}

PS:本题中,读者可以将序列:1,1,2,2,2,3,3,3,4,4,5来模拟算法的执行过程。

思考:本题中如果将有序表改为无序表,则使用散列表的时间复杂度比较低,只有O(n)。不在这里讨论。

题三:将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表。

算法思想:首先按顺序不断取下两个顺序表,表头较小的节点存入新的顺序表,然后看哪个表还有剩余,将剩余下的部分加到新的顺序表后面。

bool Merge(Seqlist A,Seqlist B,Seqlist &C)//这里的c就是返回链表
{
	if(A.Lenght+B.Length > C.maxSize) 
	return false;//这里就不考虑扩容函数
	int i =,j = 0,k = 0;//i代表A的指针,j代表B的指针 
	while(i<A.Length&&i<B.Length)
	{
		if(A.data[i]<B.data[i])
			C.data[k++] = A.data[i++];
		else
			 C.data[k++] = B.data[j++];
	 } 
	 while(i<A.Length)
	 	C.data[k++] = A.data[i++];
	while(j<B.Length)
	 	C.data[k++] = B.data[j++];
	C.Length = k+1;
	return true;

} 

这个算法非常典型,读者可以应牢固把握。

题四:已知在一个一维数组A[m+n]依次存放(两个线性表a_{1} a_{2}a_{3} a_{m} b_{1} b_{2}b_{3} b_{n}),编写一个函数,将数组中两个元素的位置互换,即将b_{1} b_{2}b_{3} b_{n}a_{1} a_{2}a_{3} a_{m}

 算法思想:通过三次逆置可求

typedef int Datatype;
void Reverse(Datatype A[],int left,int right,int arraySize) //将left和right之间进行逆转 
{
	if(left>=right || right>=arraySize||left<0)
	return false;
	int mid = (left+right)/2;
	for(int i =0;i<=mid-left;i++)
	{
		Datatype temp = A[left+i];
		 A[left+i] = A[right -i];
		 A[right-i] = temp;
	 } 
}

void Exchange(Datatype A[],int m,int n,int arraySize)
{
	Reverse(A[],0,m+n-1,int arraySize);
	Reverse(A[],0,n-1,int arraySize);
	Reverse(A[],n,m+n-1,int arraySize);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值