第一题
题目:从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。空出的位 置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行
方式一:先利用查找函数找到最小元素的序号,然后依次将元素进行前移
#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)的方式去遍历得到。
以上是所有的题目及其代码。考研加油