王道考研2020练习题 第二章 2.2 线性表 C语言实现

本文深入探讨了线性表的多种操作实现,包括插入、删除、查找等基本操作,以及更复杂的如逆置、合并、查找主要数等高级操作。通过具体算法和代码示例,详细解析了每种操作的时间和空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include "stdio.h"
#include "windows.h"
#include "stdbool.h"
#define SqListMaxSize 50
#define ElemType int
#define SeqListMaxSize 50
#define OVERFLOW 0
/*
	线性表(顺序存储结构)
*/
typedef struct {
	ElemType data[SqListMaxSize];
	int length;
}SqList;

/*
	线性表(随机存储结构)
*/
typedef struct {
	ElemType *data;
	int MaxSize, length;
}SeqList;

/*
	线性表(顺序存储结构)插入
*/
bool SqListInsert(SqList *L, int i, ElemType e) {
	if (i < 1 || i > L->length + 1)
		return false;

	if (L->length >= SqListMaxSize)
		return false;

	for (int j = L->length; j >= i; j--)
		L->data[j] = L->data[j - 1];

	L->data[i - 1] = e;
	L->length++;
	return true;
}

/*
	线性表(随机存储结构)插入
*/
bool SeqListInsert(SeqList *L, int i, ElemType e) {
	if (i < 1 || i > L->length + 1)
		return false;

	if (L->length >= SqListMaxSize)
		return false;
	for (int j = L->length; j >= i; j--)
		L->data[j] = L->data[j - 1];

	L->data[i - 1] = e;
	L->length++;
	return true;
}

/*
	线性表(随机存储结构)有序插入
*/
bool SeqListInsertByOrder(SeqList *L, ElemType e) {
	int i;

	if (L->length >= SqListMaxSize)
		return false;

	for (i = 0; i < L->length; i++) {
		if (L->data[i] >= e) {
			for (int j = L->length; j > i; j--)
				L->data[j] = L->data[j - 1];
			L->data[i] = e;
			L->length++;
			return true;
		}
	}

	L->data[L->length] = e;
	L->length++;
	return true;
}
/*
	线性表(随机存储结构)顺序插入(插到最后一位)
*/
bool SeqListInsertEnd(SeqList *L, ElemType e) {

	if (L->length >= SqListMaxSize)
		return false;
	L->data[L->length] = e;
	L->length++;
	return true;
}
/*
	线性表(顺序存储结构)删除
*/
bool SqListDelete(SqList *L, int i,ElemType *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;
}

/*
	线性表(随机存储结构)删除
*/
bool SeqListDelete(SeqList *L, int i, ElemType *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;
}

/*
	线性表(顺序存储结构)顺序查找
*/
int SqLocateElem(SqList *L, ElemType e) {
	int i;
	for (i = 0; i < L->length; i++)
		if (L->data[i] == e)
			return i + 1;
	return 0;
}

/*
	线性表(随机存储结构)随机查找
*/
int SeqLocateElem(SeqList *L, ElemType e) {
	int i;
	for (i = 0; i < L->length; i++)
		if (L->data[i] == e)
			return i + 1;
	return 0;
}

void PrintSeqList(SeqList *L) {
	int i;
	printf("线性表数据为:");
	for(i = 0; i < L->length; i++) {
		printf("[%d]%d ", i + 1, L->data[i]);
	}
	printf("\n");
}

/*
	线性表(随机存储结构)初始化
*/
bool InitSeqList(SeqList* L) {
	L->data = (ElemType*)malloc(sizeof(ElemType)*SeqListMaxSize); 
	if (!L->data) exit(OVERFLOW);
	L->length = 0;
	return true;
}

void PrintArray(ElemType A[],int length) {
	printf("数组数据为:");
	for (int i = 0; i < length; i++) {
		printf("[%d]%d ", i + 1, A[i]);
	}
	printf("\n");
}
/*
	找出最小值,并用最后的元素填充 时间复杂度O(n),空间复杂度O(1)
*/
ElemType Mos_2_2_2_1(SeqList* L) {
	int i;
	int min = L->data[0],loc = 0;
	if (!L->data) {
		printf("顺序表为空!\n");
		exit(OVERFLOW);
	}
	for (i = 0; i < L->length; i++) {
		if (L->data[i] < min) {
			min = L->data[i];
			loc = i;
		}
	}
	L->data[loc] = L->data[L->length - 1];
	L->length--;
	//SeqListDelete(&L, loc);
	return min;
}
/*
	逆置算法 时间复杂度O(n),空间复杂度O(1)
*/
void Mos_2_2_2_2(SeqList* L) {
	ElemType e;
	int i = 0;
	for (i = 0; i < L->length / 2; i++) {
		e = L->data[i];
		L->data[i] = L->data[L->length - i - 1];
		L->data[L->length - i - 1] = e;
	}
}
/*
	删除所有值为x元素的算法 时间复杂度O(n),空间复杂度O(1)
*/
void Mos_2_2_2_3(SeqList* L,ElemType x) {
	int i,k = 0;
	for (i = 0; i < L->length; i++) {
		if (L->data[i] == x) {
			k++;
		}
		else {
			L->data[i - k] = L->data[i];
		}
	}
	L->length -= k;
}
/*
	删除所有s到t之间的值的算法 时间复杂度O(n),空间复杂度O(1)
*/
void Mos_2_2_2_4(SeqList* L, ElemType s, ElemType t) {
	int i,k=0;
	if (s >= t || !L->data) {
		printf("给定值报错!\n");
		exit(OVERFLOW);
	}
	for (i = 0; i < L->length; i++) {
		if (L->data[i] < t && L->data[i] > s) {
			k++;
		}
		else {
			L->data[i - k] = L->data[i];
		}
	}
	L->length -= k;
}

/*
	删除所有s到t(包括边界)之间的值的算法 时间复杂度O(n),空间复杂度O(1)
*/
void Mos_2_2_2_5(SeqList* L, ElemType s, ElemType t) {
	int i, k = 0;
	if (s >= t || !L->data) {
		printf("给定值报错!\n");
		exit(OVERFLOW);
	}
	for (i = 0; i < L->length; i++) {
		if (L->data[i] <= t && L->data[i] >= s) {
			k++;
		}
		else {
			L->data[i - k] = L->data[i];
		}
	}
	L->length -= k;
}
/*
	删除所有相同的元素 时间复杂度O(n),空间复杂度O(n)
*/
void Mos_2_2_2_6(SeqList* L) {
	int i, k = 0;
	int rep[SeqListMaxSize] = { 0 };
	for (i = 0; i < L->length; i++) {
		rep[L->data[i]]++;
		if (rep[L->data[i]] > 1) {
			k++;
		}
		else {
			L->data[i - k] = L->data[i];
		}
	}
	L->length -= k;
}
/*
	合并两个顺序表到CL 时间复杂度O(n) 空间复杂度O(1)
*/
void Mos_2_2_2_7(SeqList* AL, SeqList* BL, SeqList* CL) {
	int i = 0, j = 0,length = AL->length + BL->length;
	CL->length = length;
	while (i + j < length) {
		if (i >= AL->length) {
			CL->data[i + j] = BL->data[j++];
			continue;
		}
		if (j >= BL->length) {
			CL->data[i + j] = AL->data[i++];
			continue;
		}
		if ( AL->data[i] < BL->data[j]) {
			CL->data[i + j] = AL->data[i++];
		}else{
			CL->data[i + j] = BL->data[j++];
		}
	}
}
/*
	将两个线性表按注入A数组,先AL,后BL
*/
void Mos_2_2_2_8_1(ElemType A[], SeqList* AL, SeqList* BL) {
	int i,j;
	for (i = 0; i < AL->length; i++) {
		A[i] = AL->data[i];
	}
	for (j = 0; j < BL->length; j++) {
		A[i+j] = BL->data[j];
	}
}
/*
	将A数组中存放的两个线性表调转位置 时间复杂度O(n) 空间复杂度O(1)
*/
void Mos_2_2_2_8(ElemType A[],int left, int right, int arraySize) {
	int i,temp;
	for (i = 0; i < arraySize / 2; i++) {
		temp = A[i];
		A[i] = A[arraySize - i - 1];
		A[arraySize - i - 1] = temp;
	}
	for (i = 0; i < right / 2; i++) {
		temp = A[i];
		A[i] = A[right - i - 1];
		A[right - i - 1] = temp;
	}
	for (i = 0; i < left / 2; i++) {
		temp = A[right+i];
		A[right + i] = A[arraySize - i - 1];
		A[arraySize - i - 1] = temp;
	}
}
/*
	使用折半查找法,找到线性表中对应的元素,并和后继元素交换位置,若找不到,则在相应位置按顺序插入该元素  
	时间复杂度O(log2n) 空间复杂度O(1)
*/
void Mos_2_2_2_9(SeqList* L, ElemType e) {
	int i,low  = 0,high = L->length - 1,mid,temp;
	while (low < high) {
		mid = (low + high) / 2;
		if (L->data[mid] == e) {
			temp = L->data[mid];
			L->data[mid] = L->data[mid + 1];
			L->data[mid + 1] = temp;
			return;
		}
		if (L->data[mid] > e) {
			high = mid - 1;
		}
		if (L->data[mid] < e) {
			low = mid + 1;
		}
	}
	for ( i = L->length - 1; i > high; i--) {
		L->data[i+1] = L->data[i];
	}
	L->data[i+1] = e;
	L->length++;
}
/*
	将A数组中的元素循环左移P位

	算法思想:
	将前p个元素看作数组B,后n-p个元素看作数组C,分别转置B与C,然后将B与C一起转置,就实现了对A数组的循环左移P位

	时间复杂度:O(n),空间复杂度O(1)
*/
void Mos_2_2_2_10(ElemType A[], int p, int arraySize) {
	int i, temp,left = p,right = arraySize - p;
	for (i = 0; i < arraySize / 2; i++) {
		temp = A[i];
		A[i] = A[arraySize - i - 1];
		A[arraySize - i - 1] = temp;
	}
	for (i = 0; i < right / 2; i++) {
		temp = A[i];
		A[i] = A[right - i - 1];
		A[right - i - 1] = temp;
	}
	for (i = 0; i < left / 2; i++) {
		temp = A[right + i];
		A[right + i] = A[arraySize - i - 1];
		A[arraySize - i - 1] = temp;
	}
}
/*
	找到AL与BL两个序列的一个中位数,[L/2](从1开始) 
	设计思想:
	1、找到AL与BL的中位数
	2、三种情况:
	(1)如果AL的中位数小于BL中位数,则舍弃AL小的一半和BL大的一半
	(2)如果AL的中位数大于BL中位数,则舍弃AL大的一半和BL小的一半
	(3)如果AL的中位数等于BL中位数,则直接返回该值
	3、在剩下的两个序列中,重复2过程,直到AL和BL都仅有一个元素,进入4
	4、返回AL和BL中较小的那一个元素作为中位数

	时间复杂度:O(log2n) 空间复杂度O(1)
*/
int Mos_2_2_2_11(SeqList *AL, SeqList *BL) {
	int lowA = 0, lowB = 0, highA = AL->length - 1, highB = BL->length - 1, midA, midB;
	while (lowA != highA || lowB != highB) {
		midA = (lowA + highA) / 2;
		midB = (lowB + highB) / 2 ;
		if (AL->data[midA] == BL->data[midB]) {
			return AL->data[midA];
		}
		if (AL->data[midA] < BL->data[midB]) {
			if ((lowA + highA) % 2 == 0) {
				lowA = midA;
				highB = midB;
			}
			else {
				lowA = midA+1;
				highB = midB;
			}
		}
		else {
			if ((lowA + highA) % 2 == 0) {
				lowB = midB;
				highA = midA;
			}
			else {
				lowB = midB+1;
				highA = midA;
			}
		}
	}
	return AL->data[lowA] < BL->data[lowB] ? AL->data[lowA] : BL->data[lowB];
}
/*
	该算法用于找出主要数,主要数的定义是,在数组中出现次数在 数组长度/2 以上的数字

	算法思想:
	1、以第一个元素为候选的主要数,然后依次向后扫描所有的数,将初始的计数值Count=1、CountMax=1
	2、如果当前元素等于候选的主要数,则Count++,CountMax++,然后进行下一次计数
	3、如果当前元素不等于候选的主要数,则判断Count是否大于0
	(1)如果不大于0,则代表候选的主要数不是真正的主要数,将当前元素设置为候选的主要数,并重置Count与CountMax
	(2)如果大于0,则使Count--
	4、在循环结束后,判断CountMax是否大于n/2,若是,则代表为主要数,若不是,则代表没有主要数反回-1

	时间复杂度O(n),空间复杂度O(1)
*/
int Mos_2_2_2_12(int A[],int length) {
	int count=1, countMax=1,c = A[0],i;
	for (i = 1; i < length; i++) {
		if (A[i] == c) {
			count++;
			countMax++;
		}
		else {
			if (count>0){
				count--;
			}
			else {
				c = A[i];
				count = 1;
				countMax = 1;
			}
		}
	}
	if (countMax > length / 2)return c;
	return -1;
}
//void Mos_2_2_2_8(ElemType A[],int right,int arraySize) {该方法有问题
//	int i = 0, j = right;
//	ElemType temp1,temp2;
//	if (right <= 0 || right >= arraySize)
//		return true;
//	for (int i = 0; i < right && right + i < arraySize; i++) {
//		temp1 = A[i];
//		temp2 = A[right+i-(arraySize-right)];
//		A[i] = A[right+i];
//		A[right + i - (arraySize - right)] = temp1;
//		A[right + i] = temp2;
//	}
//}
/*
	该算法用于找出数组A中未出现的最小正整数

	算法思路:
	利用空间换时间,制作一个长度为n的数组B,用于表示A数组中每个对应元素出现的次数
	扫描A数组,如果A[i]-1>n,那么使B数组的长度bLength--,舍弃当前元素,反之,令B[A[i]]++;
	然后扫描B数组,只要出现B[i]=0则,返回i+1作为结果,
	如果B数组中没有值为0,则返回bLength+1为结果

	时间复杂度O(n),空间复杂度O(n)
*/
int Mos_2_2_2_13(int A[], int length) {
	int B[SeqListMaxSize] = { 0 },bLength = length;
	for (int i = 0; i < length; i++) {
		if (A[i] - 1 <= length)
			B[A[i] - 1]++;
		else
			bLength--;
	}
	for (int i = 0; i < bLength; i++) {
		if (B[i] == 0) {
			return i+1;
		}
	}
	return bLength +1;
}

int main() {
	SeqList L,BL,CL,DL,EL,FL;
	ElemType A[SeqListMaxSize];
	InitSeqList(&L);
	InitSeqList(&BL);
	InitSeqList(&CL);
	InitSeqList(&DL);
	InitSeqList(&EL);
	InitSeqList(&FL);
	for (int i = 0; i < 5; i++) {
		SeqListInsertByOrder(&DL, i);
		SeqListInsertByOrder(&DL, i);
	}
	for (int i = 6; i < 10; i++) {
		SeqListInsertByOrder(&DL, i);
		SeqListInsertByOrder(&DL, i);
	}
	for (int i = 0; i < 3; i++)
		SeqListInsertEnd(&BL, i);
	for(int i = 0;i < 10;i++)
		SeqListInsertByOrder(&L, i);
	for (int i = 0; i < 3; i++)
		SeqListInsertEnd(&L, 3);
	for (int i = 0; i < 4; i++)
		SeqListInsertByOrder(&L, 2);
	for (int i = 0; i < 2; i++)
		SeqListInsertEnd(&L, 8);
	PrintSeqList(&L);
	Mos_2_2_2_1(&L);
	PrintSeqList(&L);
	Mos_2_2_2_2(&L);
	PrintSeqList(&L);
	Mos_2_2_2_3(&L,3);
	PrintSeqList(&L);
	Mos_2_2_2_4(&L, 5, 7);
	PrintSeqList(&L);
	Mos_2_2_2_5(&L, 5, 7);
	PrintSeqList(&L);
	Mos_2_2_2_6(&L);
	PrintSeqList(&L);
	Mos_2_2_2_7(&L, &BL, &CL);
	PrintSeqList(&CL);
	Mos_2_2_2_8_1(A, &L, &BL);
	PrintArray(A, L.length + BL.length);
	Mos_2_2_2_8(A, L.length,BL.length, L.length + BL.length);
	PrintArray(A,L.length + BL.length);
	PrintSeqList(&DL);
	Mos_2_2_2_9(&DL, 5);
	PrintSeqList(&DL);
	PrintArray(A, L.length + BL.length);
	Mos_2_2_2_10(A, 3, L.length + BL.length);
	PrintArray(A, L.length + BL.length);
	for (int i = 1; i < 4; i++)
		SeqListInsertByOrder(&EL, i);
	for (int i = 2; i < 5; i++)
		SeqListInsertByOrder(&FL, i);
	PrintSeqList(&EL);
	PrintSeqList(&FL);
	printf("中位数为%d\n",Mos_2_2_2_11(&EL, &FL));
	for (int i = 2; i < 5; i++)
		SeqListInsertByOrder(&FL, 3);
	Mos_2_2_2_8_1(A, &EL, &FL);
	PrintArray(A, EL.length + FL.length);
	printf("主要数为:%d \n", Mos_2_2_2_12(A, EL.length + FL.length));
	printf("未出现的最小正整数为:%d\n", Mos_2_2_2_13(A, EL.length + FL.length));
	system("pause");
	return 0;

}

注1:单链表和顺序表删除所有值为X的元素的时间复杂度应该都为O(n)参照2.2.3题,但在考研真题当中似乎是没有考虑这一点。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值