数据据结构实验——顺序表实验

这篇博客详细介绍了顺序表的各种操作,包括在指定位置插入元素、删除元素、递增有序插入、分离奇偶元素、查找两个有序序列的交集、删除重复元素、判断是否为子集以及合并和差集运算。所有操作都提供了算法设计思想和C/C++实现,强调了时间性能和空间复杂度。
摘要由CSDN通过智能技术生成

一、实验任务

编写算法实现下列问题的求解。

(1)在第i个结点位置插入值为x的结点。

实验测试数据基本要求:

第一组数据:顺序表长度n≥10,x=100,  i分别为5,n,n+1,0,1,n+2

第二组数据:顺序表长度n=0,x=100,i=5

(2)删除顺序表中第i个元素结点。

实验测试数据基本要求:

第一组数据:顺序表长度n≥10,i分别为5,n,1,n+1,0

第二组数据:顺序表长度n=0, i=5

(3)在一个递增有序的顺序表L中插入一个值为x的元素,并保持其递增有序特性。

实验测试数据基本要求:

顺序表元素为 (10,20,30,40,50,60,70,80,90,100),

x分别为25,85,110和8

(4)将顺序表L中的奇数项和偶数项结点分解开(元素值为奇数、偶数),分别放入新的顺序表中,然后原表和新表元素同时输出到屏幕上,以便对照求解结果。

实验测试数据基本要求:

第一组数据:顺序表元素为 (1,2,3,4,5,6,7,8,9,10,20,30,40,50,60)

第二组数据:顺序表元素为 (10,20,30,40,50,60,70,80,90,100)

(5)求两个递增有序顺序表L1和L2中的公共元素,放入新的顺序表L3中。

实验测试数据基本要求:

第一组

第一个顺序表元素为 (1,3,6,10,15,16,17,18,19,20)

第二个顺序表元素为 (1,2,3,4,5,6,7,8,9,10,18,20,30)

第二组

第一个顺序表元素为 (1,3,6,10,15,16,17,18,19,20)

第二个顺序表元素为 (2,4,5,7,8,9,12,22)

第三组

第一个顺序表元素为 ()

第二个顺序表元素为 (1,2,3,4,5,6,7,8,9,10)

(6)删除递增有序顺序表中的重复元素,并统计移动元素次数,要求时间性能最好。

实验测试数据基本要求:

第一组数据:顺序表元素为 (1,2,3,4,5,6,7,8,9)

第二组数据:顺序表元素为 (1,1,2,2,2,3,4,5,5,5,6,6,7,7,8,8,9)

第三组数据:顺序表元素为 (1,2,3,4,5,5,6,7,8,8,9,9,9,9,9)

二、 顺序表扩展实验

非必做内容,有兴趣的同学选做,

1. 递增有序顺序表L1、L2,对2表进行合并,并使得合并后成为一个集合,集合的元素放回L1表中保存,要求时间性能最好。

2.(递增有序)顺序表表示集合A、B,实现:

C=AB,C=AB,C=A-B

A=AB,A=AB,A=A-B

3.(递增有序)顺序表表示集合A、B,判定A是否B的子集。

4. (2011)(15 分)一个长度为L(L≥1)的升序序列S,处在第          个位置的数称为S 的中位数。例如,若序列S1=(11, 13, 15, 17, 19),则S1 的中位数是15。两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若S2=(2, 4, 6, 8, 20),则S1 和S2 的中位数是11。

    现有两个等长升序序列A 和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A 和B 的中位数。要求:

(1)给出算法的基本设计思想。

(2)根据设计思想,采用C 或C++语言描述算法,关键之处给出注释。

(3)说明你所设计算法的时间复杂度和空间复杂度。

三、算法设计

(除书上给出的基本运算(这部分不必给出设计思想),其它实验内容要给出算法设计思想

(3)递增插入:从后往前搜索,同时移动元素。当元素值大于 x时后移,重复进行,直到第一个小于等于x 元素,回退一个单元即x的插入位置。

(4)分为奇偶:建立两个新表1和2,对原表进行处理。在遍历过程中,当找到奇数时插入到新表1中;找到偶数时插入到新表2中。

(5)有序C = A交B:每次取A和B中的一个最小元素,依次插入 C表即可。

当A->data[i] < B->data[j]时,A表中当前元素较小,插入C表。执行i++ , 继续取A表的下一个元素,而j不变;

当A->data[i] > B->data[j]时,B表中当前元素较小,插入C表。执行j++, 继续取B表的下一个元素,而i不变;

当A->data[i] == B->data[j]时,A、B表元素相同,或同时插入C表,或插入 一个。同时插入,执行i++,j++,同时取下一 个元素。

重复执行上述判断、插入过程,直到A和B表中 有一个结束。

(6)删除重复元素:首先判度少于 2 个元素,直接退出。

然后,将元素分成:已经处理元素和待处理元素。分别用i,j表示。初始化i = 0, j=1。

      当data[i] == data[j],说明j指示的是i的重复元素,继续处理 j 的下一个元素,即执行j++。

当data[i] < data[j]时,因为 L 递增,所以剩下情况只能是data[i] < data[j],j 为目标元素。如果 j == i+1,说明j紧随i,无需移动元素,直接i++、j++即可。若不同j元素复制到 i+1。无论那种情况,都需要同时后移 i、j。循环执行上述操作,直到表尾。修改L的长度为 i+1。

(7)A = A 并 B:设置两个指针i、j分别指向A、B表当前处理的元素;

       当A->data[i] < B->data[j]时,A表中当前元素较小,执行i++。

当A->data[i] > B->data[j]时,B表中当前元素较小,因为递增性,j指示的元素不可能在A中,将该元素加入A后面。

当A->data[i] == B->data[j]时,A、B表元素相同,执行i++,j++,同时取下一个元素。

重复执行上述判断、插入过程,直到A和B表中 有一个结束。若A表剩余直接就在其中,若B表剩余,则全满足,加入A表后面

(8)A = A 并 B(见第7题)

A = A 交 B设置两个指针ia、ib分别指向A、B表当前处理的元素;设置一个指针 i 示已经求取的交集元素在 A 的表中的最后元素位置

当A->data[ia] == B->data[ib]时,则 ia 或 ib 是交集元素。然后让三个指针后        移ia++,ib++,i++。

当A->data[ia] < B->data[ib]时,当前元素为非交集元素,但可能在B元素后面,所以只需移动 ib。

当A->data[ia] > B->data[ib]时,同理只需要移动ia。

重复以上过程,直至 A、B 中至少一个表结束。 修改 A 表长度为 i+1。

A = A 差 B设置两个指针 ia、ib 分别指向 A、B 表当前处理的元素;设置一个指针                     指示已经求取的差集元素在 A 的表中的最后元素位置;

当A->data[ia] == B.data[ib],则ia或ib是交集元素,不是A-B 中元素,直接               跳过,执行ia++,ib++。

当A->data[ia] > B->data[ib],ia 指示的元素可能在 B 表 ib 指示的元素后面,ia不动,移动ib。

当A->data[ia] < B->data[ib],ia 指示的元素不可能在 B 中出现,故比为 A-B 中元素。需要写入A中,然后执行i++,ia++。

重复以上过程,直至 A、B 中至少一个表结束。若B 表已结束,剩下元素全为 A-B 中元素,全部迁移到目标位置。若A表已结束,则直接结束。最后,修改 A 表长度为 i+1。

C = A 并 B设置两个指针i、j、k分别指向A、B、C表当前处理的元素;

                  当A->data[i] < B->data[j]时,A表中当前元素较小,因为递增性,i指示的元素

不可能在B中,将该元素插入C表,执行i++,k++。

当A->data[i] > B->data[j]时,B表中当前元素较小,因为递增性,j指示的元素

              不可能在A中,将该元素加入C中,执行j++,k++。

当A->data[i] == B->data[j]时,A、B表元素相同,插入一个到C中,执行i++,j++,k++同时取下一个元素。

重复执行上述判断、插入过程,直到A和B表中 有一个结束。若A表剩余直接插入C中,若B表剩余,则直接插入C中。最后,修改 C 表长度。

C = A 交 B(见第5题)。

C = A 差 B设置两个指针i、j、k分别指向A、B、C表当前处理的元素;

当A->data[i] == B.data[j],则i或j是交集元素,不是A-B 中元素,直接跳过,执行i++,j++。

当A->data[i] > B->data[j],i指示的元素可能在 B 表 j指示的元素后面,i不动,移动j。

当A->data[i] < B->data[j],i指示的元素不可能在 B 中出现,故比为 A-B 中元素。需要写入C中,然后执行i++,j++, k++。

重复以上过程,直至 A、B 中至少一个表结束。若B 表已结束,剩下元素全为 A-B 中元素,全部迁移到目标位置。若A表已结束,则直接结束。最后,修改 C 表长度。

(9)是否为子集:设用ia和ib分别为A和B中元素的编号。

当A->data[ia] > B->data[ib]时,即A表中当前元素大于B表中当前元素,因而需要继续 在B表中搜索,即要执行ib++以使ib指向B表中下一个元素并继续搜索。

当A->data[ia] == B->data[ib]时,A表中当前元素在B表中,即查找成功, 同时后移。

当A->data[ia] < B->data[ib]时,即A表中当前元素小于B表中当前元素,因而肯定小于 其后面的所有元素,所以该元素肯定不在B中,所以不是子集,返回0。

重复执行上述判断过程,直到ia和ib中至少有一个指向表尾之后为止。此时,A表未结束。可返回结论1。若B表结束,可返回0。

(10)分别求两个升序序列A、B 的中位数,设为mid1和mid2。若mid1 = mid2,则mid1或mid2即为所求的中位数;否则,舍弃mid1和mid2中较小者所在序列之较小一半,同时舍弃较大者所在序列之较大一半,要求两次舍弃的元素个数相同。在保留的两个升序序列中,重复上述过程,直到两个序列中均只含一个元素时为止,则较小者即为所求的中位数。

#define MAXLEN 100
#include <iostream>

using namespace std;
typedef struct sList{
	int data[MAXLEN];
	int listLen;
}seqList; 
//初始化一个新顺序表 
void initList(seqList *&L){
	L = new seqList;
	L->listLen = 0;
}
//读取数组元素到顺序表中 
void creatList(seqList *&L, int a[], int n){
	int i, j;
	L = new seqList;	//实例化一个顺序表 
	if(n == 0){		//若为空,直接返回 
		return;
	}
	for(i = 0, j = 0; i < n; i++, j++){	//将数组元素读入顺序表中 
		L->data[j] = a[i];
	} 
	L->listLen = n;
}
//展示顺序表元素 
void displayL(seqList *L){
	if(L->listLen == 0){
		cout << "表为空!"; 
	} 
	for(int i = 0; i < L->listLen; i++){	//遍历打印出顺序表元素 
		cout << L->data[i] << " "; 
	}
	cout << endl;
}
//基本插入元素 
bool listInsert(seqList *L, int x, int i){
	bool flag = 0;
	if(L->listLen == MAXLEN)
		cout << "表满,插入错误!" << endl;	//溢出,不能插入 
	else if(i < 1 || i > L->listLen + 1)
		cout << "序号" << i << "超出范围,插入失败!" << endl;	//超出范围也不能插入 
	else{
		for(int j = L->listLen - 1; j >= i - 1; j--){
			L->data[j + 1] = L->data[j];	//后移一位 
		}
		L->data[i - 1] = x;	//插入元素 
		L->listLen++;
		flag = 1;
	}
	return flag;
}
//基本删除元素 
bool listDelete(seqList *L, int i){
	bool flag = 0;
	if(L->listLen <= 0)
		cout << "空表,删除错误!" << endl;		// 空表,不能删除
	else if(i < 1 || i > L->listLen)
		cout << "序号" << i << "超出范围,删除失败!" << endl;		//超出范围,不能删除
	else{
		for(int j = i; j <= L->listLen - 1; j++){
			L->data[j - 1] = L->data[j];			//前移一位 
		}
		L->listLen--;
		flag = 1;
	}
	return flag;
}
//递增有序插入 
void Insert(seqList *L, int x){
		int i,j;
		if(L->listLen == MAXLEN){
			cout << "表满,插入错误!" << endl;	//溢出,不能插入 
			return; 
		}
		for(i = L->listLen - 1; L->data[i] > x && i >= 0; i--){
			L->data[i+1]=L->data[i];	//指针从最后开始后移一位 
		}
		L->data[i + 1] = x;
		L->listLen++;	
}
//分为奇偶顺序表 
void part(seqList *L, seqList *A, seqList *B){
	int i = 0, j = 0, p = 0;
	while(i < L->listLen){		
		if(L->data[i] % 2 == 0)	//为偶数,进入A中 
		{
			A->data[j] = L->data[i];
			j++;
			A->listLen++;
			i++;
		}else{		//为奇数,进入B中 
			B->data[p] = L->data[i];
			p++;
			B->listLen++;
			i++;
		} 
	}
}
//C = A 交 B 
void merge(seqList *A, seqList *B, seqList *C){
	int i = 0, j = 0, k = 0;
	while (i < A->listLen && j < B->listLen){
		if (A->data[i] < B->data[j]){//A小于B,A元素可能在B元素后面,A元素后移 
			i++;
		}else if (A->data[i] > B->data[j]){
			j++;//B小于A,B元素可能在A元素后面,B元素后移
		}else{//交集元素,加入C 
			C->data[k] = B->data[j];
			j++;
			i++;
			k++;
		}
	}
	C->listLen = k;
}
//删除重复元素 
int DeleteRepeatData(seqList *L){
	int i, j, sum; 
	if(L->listLen < 2)
		return 0; //少于 2 个元素,直接退出
	i = 0; 
	j = 1;
	sum = 0;
	while(j < L->listLen){
		if(L->data[i] == L->data[j]) //j 为重复元素,j 后移
			j++;
		else{ //因为 L 递增,所以剩下情况即 L.data[i]<L.data[j],j 为目标元素
			if((i+1) != j){//如果 j==i+1,说明 j 紧随 i,无需移动元素,直接 i++、j++即可
				L->data[i+1] = L->data[j]; //j 元素复制到 i+1
				sum++;
			}
			i++; //无论那种情况,都需要同时后移 i、j
			j++;
		}
	}
	L->listLen = i+1; //修改表的实际长度
	return sum;
}
//A = A 并 B 
void Add(seqList *L1, seqList *L2){
    int i = 0, j = 0;
    while(i < L1->listLen && j < L2->listLen){
        if(L1->data[i] == L2->data[j]){//两表元素相同, 同时i++,j++,
            i++;
            j++;
        }else if(L1->data[i] < L2->data[j]){
            i++;//l1小于l2,则直接后移	 
        }else{//L1大于L2,因为递增性,j指示的元素不可能在L1中,将该元素加入L1后面 
            L1->data[L1->listLen] = L2->data[j];
            L1->listLen++;
            j++;
        }
    }//L1表剩余直接就在其中,L2表剩余,则全满足,加入L1后面 
    while(j < L2->listLen){
        L1->data[L1->listLen] = L2->data[j];
        L1->listLen++;
        j++;
    }
}
//A = A 交 B 
void InterSet(seqList *A, seqList *B){
	int i = 0; 
	int ia = 0, ib = 0; //A、B 表当前元素的数组下标
	while(ia < A->listLen && ib < B->listLen){
		if(A->data[ia] == B->data[ib]){ //ia 和 ib 指示的是交集元素
			A->data[i] = A->data[ia];
			i++;
			ia++;
			ib++;
		}else if(A->data[ia] < B->data[ib]) //以下为非交集元素处理
			ia++;
		else
			ib++;
	}
	A->listLen = i; //更新 A 表长度,使等于交集元素个数。
}
//A = A 差 B 
void SetSubtraction(seqList *A, seqList *B){
	int i = 0; //指示 A 中已经处理的最后元素
	int ia = 0, ib = 0; //指示 A、B 中,当前待处理的元素,初始指向第一个元素
	while(ia < A->listLen && ib < B->listLen ){
		if(A->data[ia] == B->data[ib]){ //元素相等,一定非 A-B 中元素,ia、ib 同时后移
			ia++;
			ib++;
		}else if(A->data[ia] > B->data[ib]) 
			ib++; //ia 指示元素可能在 B 中 ib 指示的元素后面,移动 ib。
		else{ 	//A<B,因为递增性,ia 指示的元素不可能在 B 中。
			A->data[i] = A->data[ia];
			i++; 
			ia++; 
		}
	}
//处理 B 已经,A 尚未结束情况,A 中剩下部分元素全部为 A-B 元素	
	while(ia < A->listLen) {
		A->data[i] = A->data[ia];
		i++; 
		ia++; 
	}
	A->listLen = i; //更新表 A 的长度
}
//C = A 并 B
void MergeList(seqList *A, seqList *B, seqList *C){
    int i = 0, j = 0, k = 0;
    while(i < A->listLen && j < B->listLen){
        if(A->data[i] == B->data[j]){	//A、B表元素相同,插入一个。同时i++,j++,
			C->data[k++] = A->data[i];
			i++;
			j++;
		}else if(A->data[i] < B->data[j]){	//A表中当前元素较小,插入C表。执行i++ ,
			C->data[k++] = A->data[i++];	//继续取A表的下一个元素,而j不变;
		}else{								//B表中当前元素较小,插入C表。执行j++,
			C->data[k++] = B->data[j++];	//继续取B表的下一个元素,而i不变;	
        }
    }
    //下面处理一个表结束,另一个表未结束情况
    while(i < A->listLen){
		C->data[k++] = A->data[i++];
    }
    while(j < B->listLen){
		C->data[k++] = B->data[j++];
	}
    C->listLen = k;
}
//C = A 差 B
void cha(seqList *A, seqList *B, seqList *C){
    int i = 0, j = 0, k = 0;
    while(i < A->listLen && j < B->listLen){
        if(A->data[i] == B->data[j]){ //元素相等,一定非 A-B 中元素,i、j 同时后移
			i++;
			j++;
		}else if(A->data[i] < B->data[j]){	//A<B,因为递增性,i指示的元素不可能在 B 中。
			C->data[k++] = A->data[i++];
		}else{
			j++;//i指示元素可能在 B 中j指示的元素后面,移动 j。
        }
    }//处理 B 已经,A 尚未结束情况,A 中剩下部分元素全部为 A-B 元素	
    while(i < A->listLen){
		C->data[k++] = A->data[i++];
    }
    C->listLen = k;//更新C表长度 
}
//判断是否为子集 
bool ZiJi(seqList *A, seqList *B){ 
	int ia = 0, ib = 0; 
 	while (ia < A->listLen && ib < B->listLen){
 		if (A->data[ia] == B->data[ib]){	//相等则直接下一个 
 			ia++; 
 			ib++;
 		}else if (A->data[ia]> B->data[ib]) 
			ib++;		//A数大于B,则与A相等的数可能在下一个 
 		else 
			return 0;	//A数小于B,则不可能是自己,直接返回 0 
	 }
 	//一表结束后
	if (ia >= A->listLen) 
		return 1; //A表结束
 	else
	 	return 0; //A未结束,B结束
}
//查找中位数    参考网络 
int M_Search(int A[], int B[], int n){
	int start1, end1, mid1, start2, end2, mid2; 
	start1 = 0;
	end1 = n - 1;
	start2 = 0;
	end2 = n - 1;
	while(start1 != end1 || start2 != end2){
		mid1 = (start1 + end1) / 2;
		mid2 = (start2 + end2) / 2;
		if(A[mid1] == B[mid2])
			return A[mid1];
		if(A[mid1] < B[mid2]){//分别考虑奇数和偶数,保持两个子数组元素个数相等
			if((start1 + end1) % 2 == 0){//若元素为奇数个
				start1 = mid1; //舍弃A中间点以前的部分且保留中间点
				end2 = mid2; //舍弃B 中间点以后的部分且保留中间点
			}else{ //若元素为偶数个
				start1 = mid1 + 1;//舍弃A 的前半部分
				end2 = mid2; //舍弃B 的后半部分
			}
		}else{
			if((start1 + end1) % 2 == 0){//若元素为奇数个
				end1 = mid1; //舍弃A 中间点以后的部分且保留中间点
				start2 = mid2; //舍弃B 中间点以前的部分且保留中间点
			}else{//若元素为偶数个
				end1 = mid1; //舍弃A 的后半部分
				start2 = mid2 + 1;//舍弃B 的前半部分
			}
		}
	}
	return A[start1] < B[start2] ? A[start1] : B[start2];	//取较小的为中位数 
}

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值