王道2.2.4课后代码题实现

第一题

题目:从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。空出的位 置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行
方式一:先利用查找函数找到最小元素的序号,然后依次将元素进行前移

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

//定义线性表
typedef	struct {
	ElemType data[Maxsize];
	int length;
}Sqlist;

//查找第i个元素所处位置
bool SearchMinValue(Sqlist L, ElemType& Minvalue, int &Min) { //传入顺序表、最小值、最小值位置,后两个为引用,传回实际值
	if (L.length == 0) {//判断是否是空表
		return 0;
	}
	Minvalue = L.data[0];//将最小值赋值为第一个元素
	Min = 1;//序号为1
	for (int i = 1; i < L.length; i++) {
		if (L.data[Min - 1] > L.data[i]) {//依次比较,若不是最小的则更新
			Minvalue = L.data[i];
			Min = i + 1;
		}
	}
	return 1;
}
//删除最小的元素,采用的是先利用查找函数找到最小元素的序号,然后依次将元素进行前移
bool SqlistDelete(Sqlist& L, ElemType& value) {
	ElemType Minvalue=0;
	int Min=0;
	if (SearchMinValue(L, Minvalue, Min)==0) {//判断是否为空表
		return 0;
	}
	else {
		value = Minvalue;//记录最小值
		for (int j = Min; j < L.length; j++) {
			L.data[j - 1] = L.data[j];//依次前移
		}
		L.length--;//长度减一
	}
	return 1;
}
int main() {
	//初始化顺序表
	Sqlist L;
	L.data[0] = 100;
	L.data[1] = 40;
	L.data[2] = 2;
	L.data[3] = 33;
	L.data[4] = 43;
	L.data[5] = 56;
	L.length = 6;
	ElemType value;
	if (SqlistDelete(L, value)==0) {//判断是否为空表
		printf("查找失败");
	}
	else {
		printf("%d", value);//输出最小值
	}
}
//测试数据:100 40 2 33 43 56
//测试结果,找到最小值为2
//顺序表结果:100 40 33 43 56

方式二:查找到相关元素后,直接用最后一个元素填补该元素,再length–

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

typedef struct {
	ElemType data[Maxsize];
	int length;
}Sqlist;

bool ListDelete(Sqlist& L, ElemType& minvalue) {//顺序表、引用最小值(返回)
	if (L.length == 0) {//判断是否为空
		return 0;
	}
	minvalue = L.data[0];//先假设第一个为最小值
	int min = 1;
	for (int j = min; j < L.length; j++) {
		if (L.data[min - 1] > L.data[j]) {//找到最小值及其对应的序号
			minvalue = L.data[j];
			min = j + 1;
		}
	}
	L.data[min - 1] = L.data[L.length - 1];//最后一个覆盖最小值
	L.length--;//长度--
}


//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}

int main() {
	//初始化顺序表
	Sqlist L;
	L.data[0] = 100;
	L.data[1] = 40;
	L.data[2] = 2;
	L.data[3] = 33;
	L.data[4] = 43;
	L.data[5] = 56;
	L.length = 6;
	ElemType minvalue;
	if (ListDelete(L, minvalue) == 0) {//判断是否为空表
		printf("查找失败");
	}
	else {
		printf("%d\n", minvalue);//输出最小值
		Listshow(L);//加一个输出顺序表来观察最后的数据变化
	}
}
//测试数据:100 40 2 33 43 56
//测试结果,找到最小值为2
//顺序表结果:100 40 56 33 43

第二题

题目:设计一个高效算法,将顺序表L 的所有元素逆置,要求算法的空间复杂度为O(1)。

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改
//题目:设计一个高效算法,将顺序表L 的所有元素逆置,要求算法的空间复杂度为O(1)。

//定义顺序表
typedef struct {
	ElemType data[Maxsize];
	int length;
}Sqlist;

void Reverse(Sqlist& L) {//改变元素、传入引用顺序表
	int mid = (L.length) / 2;//取中间作为分界
	int temp;
		for (int i = 0; i < mid; i++) {
			temp = L.data[i];
			L.data[i] = L.data[L.length - 1-i];//前后倒置
			L.data[L.length - 1 - i] = temp;
	}
}

//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}

int main() {
	//初始化顺序表
	Sqlist L;
	L.data[0] = 100;
	L.data[1] = 40;
	L.data[2] = 2;
	L.data[3] = 33;
	L.data[4] = 43;
	L.data[5] = 56;
	L.length = 6;
	//逆置前
	Listshow(L);
	//逆置
	Reverse(L);
	//逆置后
	Listshow(L);
}
//测试数据:100 40 2 33 43 56
//顺序表结果: 56 43 33 2 40 100

第三题

题目:对长度为n 的顺序表L, 编写一个时间复杂度为O(n)、 空间复杂度为0(1)的算法,该算 法删除线性表中所有值为x 的数据元素.

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

//定义线性表
typedef	struct {
	ElemType data[Maxsize];//顺序表的元素
	int length;//顺序表的当前长度
}Sqlist;//顺序表的定义

//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}

//本题采用三种方式实现
//方式一,函数void ListDeleteWay01(Sqlist &L,ElemType x)
void ListDeleteWay01(Sqlist& L, ElemType x) {//传入顺序表引用和删除值
	//k标记替换法,依次记录不等于x的元素个数,每找到一个+1,并将当前元素移至第k个位置
	int k = 0;
	for (int i = 0; i < L.length; i++) {
		if (L.data[i] != x)//判断是否等于
		{
			L.data[k] = L.data[i];//移动到第k个元素
			k++;//标记++
		}
	}
	L.length = k;
}

//方式二,函数void ListDeleteWay02(Sqlist &L,ElemType x)
void ListDeleteWay02(Sqlist& L, ElemType x) {//传入顺序表引用和删除值
	//k标记替换法,依次记录等于x的元素个数,每找到一个+1,并将不等于x的元素移至i-k个
	int k = 0;
	for (int i = 0; i < L.length; i++) {
		if (L.data[i] == x)//判断是否等于
		{
			k++;//标记++
		}
		else {
			L.data[i-k] = L.data[i];//移动到第k-i个元素
		}
	}
	L.length -=k;//长度-k
}

//方式三,函数void ListDeleteWay03(Sqlist &L,ElemType x)
void ListDeleteWay03(Sqlist& L, ElemType x) {//传入顺序表引用和删除值
	//每找到一个等于k的数用最后一个数替代,并将L.length--
	for (int i = 0; i < L.length; ) {
		if (L.data[i] == x)//判断是否等于
		{
			L.data[i] = L.data[L.length - 1];//用最后一个元素替代该元素
			L.length--;//长度减1,但i不自加,因为可能最后一个元素也等于x
		}
		else {
			i++;//如果不等于则i++继续判断
		}
	}

}


int main() {
	//初始化顺序表元素和长度
	ElemType a[10] = {10,8,54,8,8,64,45,8};
	Sqlist L;
	int n = 8;
	for (int i = 0; i < n; i++) {
		L.data[i] = a[i];
	}; 
	L.length = n;
	//输出删除前的顺序表元素
	Listshow(L);
	//删除x的元素
	int x = 8;
	//方法一
	//ListDeleteWay01(L, x);
	//方法二
	//ListDeleteWay02(L, x);
	//方法二
	 ListDeleteWay03(L, x);
	//输出删除后的顺序表元素
	Listshow(L);

}

第四题

题目:从有序顺序表中删除其值在给定值s 与 t 之间(要求s<t) 的所有元素,若s 或 t 不合理或顺序表为空,则显示出错信息并退出运行。

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

//定义线性表
typedef	struct {
	ElemType data[Maxsize];//顺序表的元素
	int length;//顺序表的当前长度
}Sqlist;//顺序表的定义

//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}

/*
从有序顺序表中删除其值在给定值s 与 t 之间(要求s<t)     的所有元素,若s 或 t 不合理或顺序表为空,则显示出错信息并退出运行。
*/

bool ListDeleteStoT01(Sqlist& L, ElemType s, ElemType t) {
	if (s > t || L.length == 0) {//判断是否s和t合理,以及顺序表是否为空
		return 0;
	}
	//k标记法
	int i,k=0;
	for (i = 0; i < L.length; i++) {
		if (L.data[i] >= t) {//对于大于t的元素则前移k个
			L.data[i-k] = L.data[i];
			continue;
		}
		if (L.data[i] > s) {//两者中间就对k进行累加,
			k++;
		}
		//小于s的不做处理
	}
	L.length -= k;//最后长度减k
}

int main() {
	//初始化顺序表元素和长度
	ElemType a[10] = { 1,8,16,20,38,40,45,60 };
	Sqlist L;
	int n = 8;
	for (int i = 0; i < n; i++) {
		L.data[i] = a[i];

	};
	L.length = n;
	//输出删除前的顺序表元素
	Listshow(L);
	//删除元素
	ListDeleteStoT01(L, 10, 30);
	//输出删除后的顺序表元素
	Listshow(L);
}

第五题

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

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

//定义线性表
typedef	struct {
	ElemType data[Maxsize];//顺序表的元素
	int length;//顺序表的当前长度
}Sqlist;//顺序表的定义

//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}

/*
从有序顺序表中删除其值在给定值s 与 t 之间(要求s<t)     的所有元素,若s 或 t 不合理或顺序表为空,则显示出错信息并退出运行。
*/

//方法一k标记法
bool ListDeleteStoT01(Sqlist& L, ElemType s, ElemType t) {
	if (s > t || L.length == 0) {//判断是否s和t合理,以及顺序表是否为空
		return 0;
	}
	//k标记法
	int i, k = 0;
	for (i = 0; i < L.length; i++) {
		if (L.data[i] >=t||L.data[i]<=s) {//对于大于等于t或者小于等于s的元素则前移k个
			L.data[i - k] = L.data[i];
			continue;
		}
		if (L.data[i] > s) {//两者中间就对k进行累加,
			k++;
		}
		//小于s的不做处理
	}
	L.length -= k;//最后长度减k
}

//方法2:后插法
bool ListDeleteStoT02(Sqlist& L, ElemType s, ElemType t) {
	if (s > t || L.length == 0) {//判断是否s和t合理,以及顺序表是否为空
		return 0;
	}
	//后插法,每次将最后一个元素插到该为止
	int i;
	for (i = 0; i < L.length; ) {
		if (L.data[i] < t && L.data[i] > s) {//对于在中间的数,用最后一个数替代
			L.data[i] = L.data[L.length-1 ];
			L.length--;
		}
		else {
			i++;//不在中间则后移搜索
		}
	}
}

int main() {
	//初始化顺序表元素和长度
	ElemType a[10] = { 1,20,8,38,10,15,40,6 };
	Sqlist L;
	int n = 8;
	for (int i = 0; i < n; i++) {
		L.data[i] = a[i];

	};
	L.length = n;
	//输出删除前的顺序表元素
	Listshow(L);
	//删除元素
	//方法一
	//ListDeleteStoT01(L, 10, 30);
	//方法二
	ListDeleteStoT02(L, 10, 30);
	//输出删除后的顺序表元素
	Listshow(L);
}

第六题

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

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

//定义线性表
typedef	struct {
	ElemType data[Maxsize];//顺序表的元素
	int length;//顺序表的当前长度
}Sqlist;//顺序表的定义

//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}
/*
从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同
*/
bool ListDeleteSame(Sqlist &L) {
	if (L.length == 0) {
		return 0;			//判断是否为空
	}
	int i, j,k=0;//i是代表不重复的元素移动,j是整个顺序表依次遍历、k记录有多少个重复元素
	for (i = 0, j = 1; j < L.length;j++) {
		if (L.data[i] == L.data[j]) {//如果相等则k++
			k++;
		}
		else {//如果不等就下一个L.data[i]变成L.data[j],保证了是有序且前面依次是不重复,
			i++;
			L.data[i] = L.data[j];
		}	
	}
	L.length -= k;//其实用i-j的一个关系也可以去得到k,但考试怕错还是记录保险,空间复杂度不变还是O(1).
	return 1;
}

int main() {
	//初始化顺序表元素和长度
	ElemType a[10] = { 1,8,8,20,38,38,45,60 };
	Sqlist L;
	int n = 8;
	for (int i = 0; i < n; i++) {
		L.data[i] = a[i];

	};
	L.length = n;
	//输出删除前的顺序表元素
	Listshow(L);
	//删除元素
	ListDeleteSame(L);
	//输出删除后的顺序表元素
	Listshow(L);
}

第七题

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

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

//定义线性表
typedef	struct {
	ElemType data[Maxsize];//顺序表的元素
	int length;//顺序表的当前长度
}Sqlist;//顺序表的定义

//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}

Sqlist ListMerge(Sqlist L, Sqlist L1) {
	Sqlist L2;
	L2.length = 0;//L2.length初始化
	int i, j,k;//分别代表三个顺序表的序号
	for (i = 0, j = 0,k=0; i < L.length && j < L1.length;k++) {//由于每次遍历一定会将某个元素加到L2中所以k++放到这
		if (L.data[i] < L1.data[j]) {//如果L当前元素小于L1的当前元素
			L2.data[k] = L.data[i];//将L的当前元素加到L2中
			i++;
		}
		else {
			L2.data[k] = L1.data[j];//如果L1大于等于L的元素,则将L1的加到L2中
			j++;
		}
		L2.length++;//每次对L2的长度加1,也可以放到上面去
	}
	while (i < L.length) {//若L还有剩余,遍历依次加到L2中
		L2.data[k] = L.data[i];
		i++;
		k++;
		L2.length++;
	}
	while (j < L1.length) {//若L1还有剩余,遍历依次加到L2中
			L2.data[k] = L1.data[j];
			j++;
			k++;
			L2.length++;
		}
	return L2;
}

int main() {
	//初始化顺序表元素和长度,表1
	ElemType a[10] = { 1,5,9,20,38,38,45,60 };
	Sqlist L;
	int n = 8;
	for (int i = 0; i < n; i++) {
		L.data[i] = a[i];
	}
	L.length = n;
	//初始化顺序表元素和长度,表2
	ElemType b[10] = { 6,10,14,22,32,39,40,50 };
	Sqlist L1;
	for (int i = 0; i < n; i++) {
		L1.data[i] = b[i];
	}
	L1.length = n;
	//输出合并前的顺序表元素
	Listshow(L);
	Listshow(L1);
	//合并元素
	Sqlist  L2;
	L2 = ListMerge(L, L1);
	//输出合并后的顺序表元素
	Listshow(L);
	Listshow(L1);
	Listshow(L2);
}

第八题

题目:已知在一维数组A[m+n] 中依次存放两个线性表(a₁ ,a₂ ,a₃ ,…,am)和(b₁ ,b₂ ,b₃ ,…,b,)。编写一 个函数,将数组中两个顺序表的位置互换,即将(b₁ ,b₂ ,b₃ ,…,b,)放在(a₁ ,a₂ ,a₃ ,…,am)的前面。
这里要学会一个离散数学的知识点,(A-1B-1)-1=BA。

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

//定义线性表
typedef	struct {
	ElemType data[Maxsize];//顺序表的元素
	int length;//顺序表的当前长度
}Sqlist;//顺序表的定义

//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}

//交换函数
void Reverse(Sqlist &L,int m ,int n) {
	int temp;
	for (int i = 0; i < (n - m)/2; i++)//遍历到中间
	{
		temp = L.data[m + i];//存储变量
		L.data[m + i] = L.data[n - i];//交换两个元素
		L.data[n - i] = temp;
	}
}

//顺序表位置互换
void ListExchange(Sqlist& L, int m, int n) {
	Reverse(L, 0, m-1);//将前m个元素进行交换
	Reverse(L, m , m+n-1);//将m+1到n+m+1个元素进行交换
	Reverse(L, 0, m + n-1);//全部进行交换
}
int main() {
	//初始化顺序表元素和长度
	ElemType a[20] = { 1,4,23,53,12,3,4,2,64,12,34,43,24,12,43 };
	Sqlist L;
	int n = 15;
	for (int i = 0; i < n; i++) {
		L.data[i] = a[i];
	};
	L.length = n;
	//输出交换前的顺序表元素
	Listshow(L);
	//交换元素
	int M = 10, N = 5;
	ListExchange(L, M, N);
	//输出交换后的顺序表元素
	Listshow(L);
}

第九题

题目:线性表(ai,a₂ ,a₃ ,…,an)中的元素递增有序且按顺序存储于计算机内。要求设计一个算法 完成用最少时间在表中查找数值为x 的元素,若找到,则将其与后继元素位置相交换, 若找不到,则将其插入表中并使表中元素仍递增有序

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

//定义线性表
typedef	struct {
	ElemType data[Maxsize];//顺序表的元素
	int length;//顺序表的当前长度
}Sqlist;//顺序表的定义

//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}


//有序表最快的查找,二分查找
int TwoFind(Sqlist L,ElemType x) {
	int left = 0;//定义左端点,右端点和中间点
	int right = L.length - 1;
	int mid = left + (right - left) / 2;
	while (left < right) {//如果没有查找到则left=right跳出循环

		if (L.data[mid] > x) {//如果x比中间点值小将中点变成右端点
			right = mid - 1;
			mid = left + (right - left) / 2;//重新计算中间点
		}
		else if (L.data[mid] < x) {//如果x比中间点值大将中点变成左端点
			left = mid + 1;
			mid = left + (right - left) / 2;
		}
		if (L.data[mid] == x) {//如果相等直接返回
			return mid;
		}
	}
	if (L.data[mid] > x) {//保证为比x小的最大的元素所在序号
		mid--;
	}
	return mid;
}

void ListExchange(Sqlist& L, ElemType x) {
	int mid = TwoFind(L, x);
	if(L.data[mid]==x&&mid != L.length-1) {//如果不是最后一个元素且中点值与x相等
		ElemType temp = L.data[mid];//交换前后
		L.data[mid] = L.data[mid + 1];
		L.data[mid + 1] = temp;
	}
	else {
		for (int i = L.length-1; i > mid; i--) {//如果是最后一个元素或中点值与x不等,依次后移腾出位置
			L.data[i+1] = L.data[i];
		}
		L.data[mid+1] = x;//把x插入
		L.length++;//插入元素,长度++
	}
}


int main() {
	//初始化顺序表元素和长度
	ElemType a[10] = { 1,8,16,20,38,40,45,60 };
	Sqlist L;
	int n = 8;
	for (int i = 0; i < n; i++) {
		L.data[i] = a[i];

	};
	L.length = n;
	//输出查找修改前的顺序表元素
	Listshow(L);
	//查找修改元素
	ListExchange(L, 16);
	//输出查找修改后的顺序表元素
	Listshow(L);
}

第十题

题目:设将 n(n>1) 个整数存放到一维数组R 中。设计一个在时间和空间两方面都尽可能高效的算法。将R 中保存的序列循环左移p(0<p<n) 个位置,即将R中的数据由(X0,X1, … ,Xn-1)变(Xp,Xp+1,.… ,Xn-1,X0,X,… ,Xp-1)。

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

//定义线性表
typedef	struct {
	ElemType data[Maxsize];//顺序表的元素
	int length;//顺序表的当前长度
}Sqlist;//顺序表的定义

//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}

/*
思路:观察式子和我们上面某题的思路可以保持一致:(A-1B-1)-1=BA
从而得到最后前移的式子,定义两个函数,第一个函数专门用来转置,第二个函数用来分段转置
*/

void Reserve(Sqlist &L ,int left,int right) {
	int temp;
	for (int i = 0; i <= (right - left) / 2; i++)
	{	
		temp = L.data[left + i];
		L.data[left + i] = L.data[right - i];
		L.data[right - i] = temp;
	}
}
void Exchange(Sqlist& L, int p) {
	Reserve(L, 0, p - 1);
	Reserve(L, p, L.length - 1);
	Reserve(L, 0, L.length - 1);
}

int main() {
	//初始化顺序表元素和长度
	ElemType a[10] = { 1,8,16,20,38,40,45,60 };
	Sqlist L;
	int n = 8;
	for (int i = 0; i < n; i++) {
		L.data[i] = a[i];

	};
	L.length = n;
	//输出前移前的顺序表元素
	Listshow(L);
	//前移元素
	Exchange(L, 3);
	//输出前移后的顺序表元素
	Listshow(L);
}

时间复杂度:O(n),空间复杂度O(1)

第11题

题目:一个长度为 L(L≥1) 的升序序列 S, 处在第[L/2]个位置的数称为 S 的中位数。例如,若序列S₁=(11,13,15,17,19), 则 S₁ 的中位数是15,两个序列的中位 数是含它们所有元素的升序序列的中位数。例如,若S2=(2,4,6,8,20), 则 S₁ 和 S₂ 的中位数是11。现在有两个等长升序序列A 和 B, 试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A 和 B 的中位数。

#include<stdio.h>

#define Maxsize 50//顺序表最大长度
typedef int ElemType;//将int进行别名为ElementType便于修改

//定义线性表
typedef	struct {
	ElemType data[Maxsize];//顺序表的元素
	int length;//顺序表的当前长度
}Sqlist;//顺序表的定义

//输出顺序表
void Listshow(Sqlist L) {//只需传入顺序表,不需要传入引用
	for (int i = 0; i < L.length; i++)//依次后移输出
	{
		printf("%3d ", L.data[i]);//格式输出
	}
	printf("\n");//换行保证格式
}

//方式一:
//既然是中位数,然后两个表的大小相等设为n,那么一定是
int MidResearch(Sqlist L,Sqlist L1,int n) {
	int i, j;
	for (i = 0, j = 0; i + j < n-1;) {//直至i和j的最小的为中位数,即第n/2个数
		if (L.data[i] > L1.data[j]) {//如果是L当前的数更大,则L1找下一个
			j++;
		}
		else {//同理,L找下一个
			i++;
		}
	}
	if (L.data[i] > L1.data[j]) {//判断中位数是哪一个
		return L1.data[j];
	}
	else {
		return L.data[i];
	}
}
//时间复杂度为O(n),空间复杂度为O(1)

//方式二:王道解法,可能是408标答
//二分法查找。分别在两个算法内求中位数
//① 若 a = b, 则 a 或 b 即为所求中位数,算法结束。
//② 若 a<b, 则舍弃序列A中较小的一半,同时舍弃序列B 中较大的一半,要求两次舍弃的长度相等。
//③ 若 a>b, 则舍弃序列A中较大的一半,同时舍弃序列B 中较小的一半,要求两次舍弃的长度相等。
int M_Search(Sqlist L,Sqlist L1,int n) {
	int s1 = 0, d1 = n - 1, m1, s2 = 0, d2 = n - 1, m2;
	//分别表示L和L1中的首位数、末位数和中位数
	while (s1 != d1 || s2 != d2) {
		m1 = (s1 + d1) / 2;
		m2 = (s2 + d2) / 2;
		if (L.data[m1] == L1.data[m2]) {
			return L.data[m1];			//条件1
		}
		if (L.data[m1] < L1.data[m2]) {//条件2
			if ((s1 + d1) % 2 == 0) {//若元素个数为奇数
				s1 = m1;		//舍弃L中间点以前部分且保留中间点。
				d2 = m2;		//舍弃L1中间点以后部分且保留中间点。
			}
			else {				//若元素个数为偶数
				s1 = m1 + 1;	//舍弃L中间点及中间点以前部分。
				d2 = m2;		//舍弃L1中间点以后部分且保留中间点。
			}
		}
		else              //满足条件3
		{
			if ((s2 + d2) % 2 == 0) {//若元素个数为奇数
				d1 = m1;	//舍弃L中间点以后部分且保留中间点。
				s2 = m2;	//舍弃L1中间点以前部分且保留中间点。
			}
			else {              //若元素个数为偶数
				d1 = m1;//舍弃L中间点及中间点以前部分。
				s2 = m2 + 1;//舍弃L1中间点以后部分且保留中间点。
			}
		}
	}
	return L.data[s1] < L1.data[s2] ? L.data[s1] : L1.data[s2];

}
int main() {
	//初始化顺序表元素和长度
	ElemType a[10] = { 11,13,15,17,19 };
	Sqlist L;
	int n = 5;
	for (int i = 0; i < n; i++) {
		L.data[i] = a[i];

	};
	L.length = n;
	ElemType b[10] = { 2,4,6,8,20 };
	Sqlist L1;
	for (int i = 0; i < n; i++) {
		L1.data[i] = b[i];

	};
	L1.length = n;
	//输出顺序表元素
	Listshow(L);
	Listshow(L1);
	//查找中位数
	// 方法一
	//printf("%d", MidResearch(L, L1, n));
	//方法二
	printf("%d", M_Search(L, L1, n));
}

时间复杂度:方法一O(n),方法2O(log2n),空间复杂度O(1)。建议在考场使用第一种而不是第二种,第二种更易错,当然大佬没话说。

第十二题

题目:已知一个整数序列A=(ao,a₁ ,…,an-), 其中0≤a₁<n(0≤i<n)。 若存在ap1=ap2= ·=apm=x 且 m>n/2(0≤px<n,1≤k≤m), 则 称x 为 A 的主元素。例如A=(0,5,5,3,5,7,5,5), 则5为主元素;又如A=(0,5,5,3,5,1,5,7), 则 A 中没有主元素。假设A 中 的n 个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出A 的主元素。若存在主元素,则输出该元素;否则输出-1。

#include<stdio.h>
#include "malloc.h"

//方法一:空间换时间
int Major_count(int A[],int n) {
	int* arr = (int*)malloc(sizeof(int) * (n+1));
	for (int i = 0; i < n; i++)//把数组置0
	{
		arr[i] = 0;
	}
	arr[n+1] = '\0';
	for (int i = 0; i < n; i++) {//统计每个数的出现次数
		arr[A[i]] += 1;
	}
	for (int i = 0; i <n; i++) {
		if (arr[i] > n / 2) {//如果有大于n/2的则为主元素
			return i;
		}
	}
	return -1;//前面没有返回则返回-1,说明没有主元素
}
//方法二:计数法
//① 选取候选的主元素。依次扫描所给数组中的每个整数,将第一个遇到的整数Num 保存到 c 中,记录Num 的出现次数为1; 
//若遇到的下一个整数仍等于Num, 则计数加1, 否则计 数减1; 当计数减到0时,将遇到的下一个整数保存到 c 中,
//计数重新记为1, 开始新一 轮计数,即从当前位置开始重复上述过程,直到扫描完全部数组元素。
//② 判断c  中元素是否是真正的主元素。再次扫描该数组,统计 c  中元素出现的次数,若大 于 n / 2, 则为主元素;否则,序列中不存在主元素。
int Majority(int A[], int n) {
	int i, c, count = 1;
	c = A[0];//c用来保存候选主元素,count用来计数。设置A[0]为候选主元素
	for (int i = 1; i < n; i++) {//查找候选主元素
		if (A[i] == c) {
			count++;//对候选主元素进行计数
		}
		else {
			if (count > 0) {//处理不是候选主元素的情况
				count--;
			}
			else {//更换候选主元素,重新计数
				c = A[i];
				count = 1;
			}
		}
	}
	if (count > 0) {
		for (i = count = 0; i < n; i++) {//统计可能为候选主元素的实际出现个数
			if (A[i] == c) {
				count++;
			}
		}
	}
	if (count > n / 2) return c;//如果次数大于n/2则为候选主元素
	else
	{
		return -1;//否则不是
	}
}
int main() {
	int a[10] = { 0,5,5,3,5,7,5,5 };
	int n = 8;
	//方式一
	//int major = Major_count(a, n);
	int major = Majority(a, n);
	if (major == -1) {
		printf("没有主元素");
	}
	else {
		printf("%d", major);
	}
}

方法一:时间复杂度为O(n),空间复杂度为O(n),方法二时间复杂度为O(n),空间复杂度为O(1).

第十三题

题目:给定一个含 n(n≥1) 个整数的数组,请设计一个在时间上尽可能高 效的算法,找出数组中未出现的最小正整数。例如,数组{-5,3,2,3}中未出现的最小正
整数是1;数组{1,2,3}中未出现的最小正整数是4。

#include<stdio.h>
#include "malloc.h"
#include<string.h>

//空间换时间
int findMissMin(int A[], int n) {
	int i, * B;
	B = (int*)malloc(sizeof(int) * n);//分配内存
	memset(B, 0, sizeof(int) * n);//赋初值为0
	for (i = 0; i < n; i++) {
		if (A[i] > 0 && A[i] <= n) {//介于之间则标记B
			B[A[i] - 1] = 1;
		}
	}
	for (i = 0; i < n; i++) {
		if (B[i] == 0)break;//如果存在为0的就返回i+1
	}
	return i + 1;

}

int main() {
	int a[10] = { 0,1,3,15,17,19 };
	int n = 6;
	printf("%d",findMissMin(a, n));
}

时间复杂度:O(n)。空间复杂度O(n),由于本题只需要尽可能时间高效,所以可以采用空间换时间的方式求解。

第十四题

题目:定义三元组(a,b,c)(a,b,c 均为整数)的距离D= |a-b |+ |b-c |+|c-a |。给定3个非空整数集合Si、S₂和S3, 按升序分别存储在3个数组中。请设计一个尽可能高效的算法,计算并输出所有可能的三元组(a,b,c)(a∈Si,b∈S2,c∈S₃) 中的最小距离。例如 S₁={-1,0,9},S₂={-25,-10,10,11},S3={2,9,17,30,41}, 则最小距离为2,相应的三元组为(9,10,9)。

思路:
① 使用D_min 记录所有已处理的三元组的最小距离,初值为一个足够大的整数。
② 集合S1 、S₂ 和 S₃ 分别保存在数组A 、B 、C 中。数组的下标变量i=j=k=0, 当 i< |S1|、
j< |S₂ |且k< |S3 |时 (IS表示集合S 中的元素个数),循环执行下面的a)~c)。
a) 计算(A[i], B[j],C[k])的距离D; (计算D)
b) 若D<Dmin, 则Dmin=D; (更新D)
c) 将 A[i]、B[i]、C[k]中的最小值的下标+1; (对照分析:最小值为a, 最大值为c, 这里
c 不变而更新a, 试图寻找更小的距离D)
③ 输出Dmin, 结束。

#include<stdio.h>
#include "malloc.h"
#include<string.h>



#define INT_MAX 0x7ffffff
int abs_(int a) {//计算绝对值函数
	if (a < 0) {
		return -a;
	}
	else {
		return a;
	}
}
bool xls_min(int a, int b, int c) {//判断第一个元素是否为三个数的最小值
	if (a <= b && a <= c) {
		return true;
	}
	else {
		return false;
	}
}

int findMinofTrip(int A[], int n, int B[], int m, int C[], int p) {
	//D_min用于记录三元组的最小距离,初值赋为INT_MAX
	int i = 0, j = 0, k = 0, D_min = INT_MAX, D=0;
	while (i < n && j < m && k<p && D_min>0) {
		D = abs_(A[i] - B[j]) + abs_(B[j] - C[k]) + abs_(C[k] - A[i]);//计算D
		if (D < D_min) D_min = D;   //更新D
		if (xls_min(A[i], B[j], C[k])) i++;  //更新a
		else if (xls_min(B[j], C[k], A[i])) j++;   
		else k++;
	}
	return D_min;
}
#define Maxsize 50//顺序表最大长度
int main() {
	int a[10] = {-1,0,9 };
	int b[10] = {-25,-10,10,11};
	int c[10] = {2,9,17,30,41};
	printf("%d", findMinofTrip(a, 3, b, 4, c, 5));
}

时间复杂度为O(n),空间复杂度为O(1).若考场想不到这种方法,则可以采用O(n3)的方式去遍历得到。
以上是所有的题目及其代码。考研加油

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值