线性表的顺序表示详细讲解
题面:从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。
空出的位置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行。
审题:顺序表 删除 最小值元素(唯一) 返回元素值 最后一位填补 显示错误信息
思路:传入顺序表 判空 遍历找最小值 函数与最小值类型相同 和最后一位交换值
算法实现:
ElemType Del_Min(Sqlist &L){
if ( L.length==0 ) { //判空并输出错误信息
printf("警告:顺序表为空\n");
return 0;
}
ElemType minn=L.data[0]; //假定0号元素值最小
int miid=0;
for ( int i=1 ; i<L.length ; i++ ){ //遍历寻找具有最小值的元素
if ( L.data[i]<minn ){
minn=L.data[i];
miid=i;
}
}
L.data[miid]=L.data[L.length-1]; //空出的位置由最后一个元素填补
L.length--; //删除最后一个元素
return minn; //由函数返回被删元素的值
}
题面:设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)。
审题:顺序表 所有元素逆置 空间复杂度为O(1) 高效算法
思路:不能借助新的数据结构存储,直接交换原有顺序表的值 每次交换两个只需要遍历一半
算法实现:
void Reverse(Sqlist &L){
ElemType tmp; //用于交换
for ( int i=0 ; i<L.length/2 ; i++){ //遍历一半顺序表
tmp=L.data[i];
L.data[i]=L.data[L.length-1-i];
L.data[L.length-1-i]=tmp;
}
return ;
}
题面:对长度为n的顺序表L,编写一个时间复杂度为O(n)、空间复杂度为O(1)的算法,该算法删除线性表中所有值为x的数据元素。
审题:顺序表 删除值为x的元素 时间复杂度为O(n) 空间复杂度为O(1)
思路:普通删除时间复杂度为O(n),删除m个x时间复杂度为O(n*m)不可行。遍历一次删除所有x的同时找到所有不为x值元素所在位置
算法实现:
void Del_x(Sqlist &L,ElemType x){
int k=0; //记录当前是第几个不为x的元素
for ( int i=0 ; i<L.length ; i++ ){
if ( L.data[i]!=x ){
L.data[k]=L.data[i];
k++;
}
}
L.length=k; //修改顺序表长度
}
题面:从有序顺序表中删除其值在给定值s与t之间(要求s
思路:顺序表有序,则只需要删除一段连续空间即可
算法实现:
void Del_s_t(Sqlist &L,ElemType s,ElemType t){
if ( s > t ){
printf("警告:s>t不合理\n");
return ;
}
if ( L.length==0 ) { //判空并输出错误信息
printf("警告:顺序表为空\n");
return ;
}
int k=0; //记录当前是第几个不为s与t之间的元素
for ( int i=0 ; i<L.length ; i++ ){
if ( L.data[i]<s ) k++;
if ( L.data[i]>t ){
L.data[k]=L.data[i];
k++;
}
}
L.length=k; //修改顺序表长度
return ;
}
题面:从顺序表片删除其值在给定值s与t之间(包含s和t,要求s<1)的所有元素,若s或t不合理或顺序表为空,则显示出错信息并退出运行。
审题:顺序表 删除值为s与t之间的元素 显示出错信息
思路:与第三题类似,找到小于s或大于t的元素的位置即可
算法实现:
void Del_s_t2(Sqlist &L,ElemType s,ElemType t){
if ( s > t ){
printf("警告:s>t不合理\n");
return ;
}
if ( L.length==0 ) { //判空并输出错误信息
printf("警告:顺序表为空\n");
return ;
}
int k=0; //记录当前是第几个不为s与t之间的元素
for ( int i=0 ; i<L.length ; i++ ){
if ( L.data[i]<s || L.data[i]>t ){
L.data[k]=L.data[i];
k++;
}
}
L.length=k;
return ;
}
题面:从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同。
审题:有序顺序表 删除重复的元素
思路:顺序表有序则相同元素位置连续,保留其中一个即可
算法实现:
void Del_Same(Sqlist &L){
if ( L.length==0 ) { //判空并输出错误信息
printf("警告:顺序表为空\n");
return ;
}
int k=1; //记录当前是第几个不为重复的元素
for ( int i=1 ; i<L.length ; i++ ){
if ( L.data[i]!=L.data[i-1] ){
L.data[k]=L.data[i];
k++;
}
}
L.length=k;
}
题面:将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表
审题:两个有序顺序表 合并 一个新的有序顺序表 函数返回结果顺序表
思路:按顺序不断将两表头较小元素放入新表中
算法实现:
bool Merge(Sqlist A,Sqlist B,Sqlist &C){
if ( A.length+B.length>MaxSize ) return false; //合并后超过C的最大长度
int i=0,j=0,k=0; //分别为ABC的指针
while ( i<A.length && j<B.length ){ //依次放入两表头较小元素
if ( A.data[i]<B.data[j] )
C.data[k++]=A.data[i++];
else
C.data[k++]=B.data[j++];
}
while ( i<A.length ) //A有剩余
C.data[k++]=A.data[i++];
while ( j<B.length ) //B有剩余
C.data[k++]=B.data[j++];
C.length=k; //修改C的长度
return true;
}
题面:已知在一维数组 A[m+n]中依次存放两个线性表(a1, a2, a3,…, am)和(b1, b2,b3,…, bn)。试编写一个函数,将数组中两个顺序表的位置互换,即将(b1,b2, b3,…, bn,)放在(a1, a2,a3.…, am)的前面。
审题:一维数组 两个顺序表 位置互换
思路:要使(a,b,c,d,e,f,g) -> (e,f,g,a,b,c,d)
可以先(a,b,c,d,e,f,g) -> (g,f,e,d,c,b,a) 再 ((g,f,e),(d,c,b,a)) -> ((e,g,f),(a,b,c,d))需要进行三次逆置
算法实现:
void Reverse(ElemType A[],int left,int right){ //逆置函数
ElemType tmp;
int mid=(right+left)/2;
for ( int i=0 ; i<=mid-left ; i++ ){
tmp=A[left+i];
A[left+i]=A[right-i];
A[right-i]=tmp;
}
return ;
}
void Exchange(ElemType A[],int m,int n){
Reverse(A,0,m+n-1); //(a,b,c,d,e,f,g) -> (g,f,e,d,c,b,a)
Reverse(A,0,n-1); //((g,f,e),(d,c,b,a)) -> ((e,g,f),(d,c,b,a))
Reverse(A,n,m+n-1); //((e,g,f),(d,c,b,a)) -> ((e,g,f),(a,b,c,d))
}
题面:线性表(a, a2, a3,…, an)中的元素递增有序且按顺序存储于计算机内.要求设计一个算法,完成用最少时间在表中查找数值为x的元素,若找到,则将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍递增有序。
审题:线性表 递增有序 查找 数值为x的元素 与后继元素位置相交换 插入表中 仍递增有序 最少时间
思路:对于有序序列的高效查找可以采用二分法,找到第一个大于等于x的元素
算法实现:
void SearchExchangeInsert(ElemType A[],ElemType x,int length){
int left=0,right=length-1,mid;
while ( left!=right ){ //二分法查找
mid=(left+right)/2;
if ( A[mid]==x ) break;
else if ( A[mid]<x ) left=mid+1;
else right=mid-1;
}
if ( A[mid]==x && mid!=length-1 ){ //找到x 与后继元素位置相交换
ElemType t=A[mid+1];
A[mid+1]=A[mid];
A[mid]=t;
}
if ( A[mid]!=x ){ //没找到x 插入表中
}
return ;
}
题面:设将n(n>1)个整数存放到一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(0
审题:数组 n(n>1)整数 循环左移 p(0
思路:要使(1,2,3,4,5,6,7) p=3-> (5,6,7,1,2,3,4)
可以先(1,2,3,4,5,6,7) -> (7,6,5,4,3,2,1) 再 ((7,6,5),(4,3,2,1)) -> ((5,6,7),(1,2,3,4))
算法实现:
void Reverse(int A[],int left,int right){ //逆置
int tmp,mid=(right+left)/2;
for ( int i=0 ; i<=mid-left ; i++ ){
tmp=A[left+i];
A[left+i]=A[right-i];
A[right-i]=tmp;
}
return ;
}
void Converse(int A[],int n,int p){
Reverse2(A,0,n-1); //(1,2,3,4,5,6,7) -> (7,6,5,4,3,2,1)
Reverse2(A,0,p-1); //((7,6,5),(4,3,2,1)) -> ((5,6,7),(4,3,2,1))
Reverse2(A,p,n-1); //((5,6,7),(4,3,2,1)) -> ((5,6,7),(1,2,3,4))
}
题面:一个长度为L(L≥1)的升序序列S,处在第[L/2]个位置的数称为S的中位数。 例如,若序列S1=(11,13,15,17,19),则S1的中位数是15,两个序列的中位数是含它们所有元素的升序序列的中位数。 例如,若S2=(2,4,6,8,20),则S1和S2的中位数是11。现在有两个等长升序序列A和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。
审题:中位数 第[L/2]个位置 等长升序序列 找出两个序列A和B的中位数
思路一:先有序合并两序列,再找到中位数,时空复杂度均为O(n)
思路二:思路二:利用已知条件,可以快速找到A,B各自中位数a,b
若a==b,则序列A和B的中位数为 a或b
若a>b ,则删去A中较大的一半,B中较小的一半,删去相同的长度
若a 循环上述过程,直到A,B都只剩1个元素,取较小的一个
时间复杂度:O(log2n),空间复杂度:O(1)
算法实现:
int M_Search1(int A[],int B[],int n){
int C[n*2];
int i=0,j=0,k=0;
while ( i<n && j<n ){
if ( A[i]<B[j] )
C[k++]=A[i++];
else
C[k++]=B[j++];
}
while ( i<n )
C[k++]=A[i++];
while ( j<n )
C[k++]=B[j++];
// printf("\n");
// for ( int i=0 ; i
return C[n-1];
}
int M_Search2(int A[],int B[],int n){
int s1=0,e1=n-1,m1;
int s2=0,e2=n-1,m2;
while ( s1!=e1 || s2!=e2 ){
m1=(s1+e1)/2;
m2=(e2+s2)/2;
if( A[m1]==B[m2] ) return A[m1];//若a==b,则序列A和B的中位数为 a或b
else if( A[m1]>B[m2] ){ //若a>b ,则删去A中较大的一半,B中较小的一半
if ((s1+e1)%2==0) //保证删去相同的长度
e1=m1,s2=m2;
else
e1=m1,s2=m2+1;
}
else{ // 若a
if ((s1+e1)%2==0) 保证删去相同的长度
s1=m1,e2=m2;
else
s1=m1+1,e2=m2;
}
}
return A[s1]<B[s2] ? A[s1] : B[s2];//A,B都只剩1个元素,取较小的一个
}
题面:已知一个整数序列A=(a0,a1,…,an-1),其中0
思路:可以排序后,遍历一遍得答案时间复杂度O(nlog2n);也可以遍历时记录当前能做主元素得值的个数时间复杂度O(n),比较难想到
算法实现:
int Majority(int A[],int n){
int i,x=A[0],count=1;
for ( i=1 ; i<n ; i++ ){
if ( A[i]==x ) count++;
else{
if ( count ) count--;
else {
x=A[i];
count++;
}
}
}
if ( count )
for ( i=count=0 ; i<n ; i++ )
if ( A[i]==x ) count++;
if ( count>n/2 ) return x;
else return -1;
}
题面:给定一个含n(n>=1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。例如,数组{-5,3,2,3}中 未出现的最小正整数是1;数组{1,2,3}中未出现的最小正整数是4。
审题:整数数组 时间高效 未出现的 最小正整数
思路:利用一个新的数组记录当前出现过的1-n的数
算法实现:
int FindMissMin(int A[],int n){
int i,B[n+5]; //B作为标记数组
for ( i=0 ; i<n ; i++ )
if ( A[i]>0 && A[i]<=n ) B[A[i]]++;//标记出现过的数
for ( i=1 ; i<=n ; i++ )
if ( B[i]==0 ) break;//找到第一个未出现的正整数
return i;
}
题面:定义三元组(a, b,c) (a、b、c均为正数)的距离D=|a-b|+|b-c+|c-a|。给定3个非空整数集合S1、S2和S3, 按升序分别存储在3个数组中。请设计一个尽可能高效的算法,计算并输出所有可能的三元组(a,b,c) (a∈S1,b∈S2, c∈S3) 中的最小距离。例如S1={-1,0,9}, S2={-25,-10,10,11}, S3={2,9, 17,30, 41},则最小距离为2,相应的三元组为(9, 10,9)。
审题:整数集合 升序数组 三元组(a,b,c) 最小距离
思路:对于一个三元组D的大小取决于最大值与最小值的差(建立自己举例理解这句话)。为了找最小的D可以固定最大值,每次改变最小值,计算并更新D
算法实现:
bool xls_min(int a,int b,int c){//判断a是否为3数中最小的一个
return( a<=b && a<=c);
}
int FindMinofTrip(int A[],int n,int B[],int m,int C[],int p){
int i=0,j=0,k=0,D_min=INF,D;
while( i<n && j<m && k<p && D_min>0 ){
D=fabs(A[i]-B[j])+fabs(B[j]-C[k])+fabs(A[i]-C[k]);//计算D
D_min=min(D_min,D);//更新D
if( xls_min(A[i],B[j],C[k]) ) i++; //将最小值下标加一
else if ( xls_min(B[j],A[i],C[k]) ) j++;
else k++;
}
return D_min;
}
#include
using namespace std;
typedef int ElemType; //线性表元素数据类型
const int INF=0x3f3f3f3f;
//静态分配
#define MaxSize 50 //线性表最大长度
typedef struct{
ElemType data[MaxSize]; //顺序表的元素
int length; //顺序表的当前长度
}Sqlist; //顺序表的类型定义
ElemType Del_Min(Sqlist &L);
void Reverse(Sqlist &L);
void Del_x(Sqlist &L,ElemType x);
void Del_s_t(Sqlist &L,ElemType s,ElemType t);
void Del_s_t2(Sqlist &L,ElemType s,ElemType t);
void Del_Same(Sqlist &L);
bool Merge(Sqlist A,Sqlist B,Sqlist &C);
void Exchange(ElemType A[],int m,int n);
void SearchExchangeInsert(ElemType A[],ElemType x,int length);
void Converse(int A[],int n,int p);
int M_Search1(int A[],int B[],int n);
int M_Search2(int A[],int B[],int n);
int Majority(int A[],int n);
int FindMissMin(int A[],int n);
int FindMinofTrip(int A[],int n,int B[],int m,int C[],int p);
//1-7题
void test1(){
//初始化
Sqlist L;
L.length=0;
for ( int i=0 ; i<10 ; i++ ){
L.data[i]=rand()%20;
L.length++;
}
Sqlist LA;
LA.length=0;
for ( int i=0 ; i<5 ; i++ ){
LA.data[i]=rand()%20;
LA.length++;
}
Sqlist LB;
LB.length=0;
for ( int i=0 ; i<5 ; i++ ){
LB.data[i]=rand()%20;
LB.length++;
}
Sqlist LC;
LC.length=0;
sort(L.data,L.data+L.length); //排序
sort(LA.data,LA.data+LA.length); //排序
sort(LB.data,LB.data+LB.length); //排序
//输出
// for ( int i=0 ; i
for ( int i=0 ; i<LA.length ; i++ ) printf("LA.data[%d]=%d\n",i+1,LA.data[i]);
for ( int i=0 ; i<LB.length ; i++ ) printf("LB.data[%d]=%d\n",i+1,LB.data[i]);
// printf("删除了%d\n",Del_Min(L));
// Reverse(L);
// Del_x(L,18);
// Del_s_t(L,10,20);
// Del_s_t2(L,10,20);
// Del_Same(L);
Merge(LA,LB,LC);
//输出
// for ( int i=0 ; i
for ( int i=0 ; i<LC.length ; i++ ) printf("LC.data[%d]=%d\n",i+1,LC.data[i]);
return ;
}
//8-14题
void test2(){
//初始化
// ElemType A[50],B[50];
// for ( int i=0 ; i<10 ; i++){
// A[i]=rand()%10;
// B[i]=rand()%10+8;
// }
//排序
// sort(A,A+10);
// sort(B,B+10);
//输出
// printf("\n");
// for ( int i=0 ; i<10 ; i++) printf("A[%d]=%d\n",i+1,A[i]);
// printf("\n");
// for ( int i=0 ; i<10 ; i++) printf("B[%d]=%d\n",i+1,B[i]);
// Exchange(A,4,6);
// SearchExchangeInsert(A,5,10);
// Converse(A,10,4);
// printf("序列A和B的中位数是%d\n",M_Search1(A,B,10));
// printf("序列A和B的中位数是%d\n",M_Search2(A,B,10));
// printf("序列A主元素是%d\n",Majority(A,10));
// printf("序列A中未出现的最小正整数是%d\n",FindMissMin(A,10));
int A[3]={-1,0,9},B[4]={-25,-10,10,11},C[5]={2,9,17,30,41};
printf("最小距离是%d\n",FindMinofTrip(A,3,B,4,C,5));
//输出
// printf("\n");
// for ( int i=0 ; i<10 ; i++) printf("A[%d]=%d\n",i+1,A[i]);
}
int main(){
// test1();
test2();
return 0;
}
//***14.【2020统考真题】定义三元组(a, b,c) (a、b、c均为正数)的距离D=|a-b|+|b-c+|c-a|。
//给定3个非空整数集合S、S2和S3, 按升序分别存储在3个数组中。请设计一个尽可能高效的算法,
//计算并输出所有可能的三元组(a,b,c) (a∈S1,b∈S2, c∈S3) 中的最小距离。
//例如S1={-1,0,9}, S2={-25,-10,10,11}, S3={2,9, 17,30, 41},则最小距离为2,相应的三元组为(9, 10,9)。要求:
//1)给出算法的基本设计思想。
//2)根据设计思想,采用C语言或C++语言描述算法,关键之处给出注释。
//3)说明你所设计算法的时间复杂度和空间复杂度。
bool xls_min(int a,int b,int c){
return( a<=b && a<=c);
}
int FindMinofTrip(int A[],int n,int B[],int m,int C[],int p){
int i=0,j=0,k=0,D_min=INF,D;
while( i<n && j<m && k<p && D_min>0 ){
D=fabs(A[i]-B[j])+fabs(B[j]-C[k])+fabs(A[i]-C[k]);
D_min=min(D_min,D);
if( xls_min(A[i],B[j],C[k]) ) i++;
else if ( xls_min(B[j],A[i],C[k]) ) j++;
else k++;
}
return D_min;
}
//13.【2018统考真题】给定一个含n(n>=1)个整数的数组,请设计一个在时间上尽可能高效的算法,
//找出数组中未出现的最小正整数。例如,数组{-5,3,2,3}中 未出现的最小正整数是1;数组{1,2,3}中未出现的最小正整数是4。要求:
//1)给出算法的基本设计思想。
//2)根据设计思想,采用C或 C++语言描述算法关键之处给出注释。
//3)说明你所设计算法的时间复杂度和空间复杂度。
//审题:整数数组 时间高效 未出现的 最小正整数
int FindMissMin(int A[],int n){
int i,B[n+5];
for ( i=0 ; i<n ; i++ )
if ( A[i]>0 && A[i]<=n ) B[A[i]]++;
for ( i=1 ; i<=n ; i++ )
if ( B[i]==0 ) break;
return i;
}
//***12.【2013统考真题】已知一个整数序列A=(a0,a1,...,an-1),其中0n/2(0<=pk
//例如A=(0,5,5,3,5,7,5,5),则5为主元素;又如A=(0,5,5,3,5,1,5,7),则A中没有主元素。假设A中的n个元素保存在一个一维数组中,
//请设计一个尽可能高效的算法,找出A的主元素。若存在主元素,则输出该元素;否则输出-1。要求
//1)给出算法的基本设计思想。
//2)根据设计思想,采用C或 C++或 Java语言描述算法,关键之处给出注释。
//3)说明你所设计算法的时间复杂度和空间复杂度。
//审题:整数序列 主元素 众数个数大于n/2
int Majority(int A[],int n){
int i,x=A[0],count=1;
for ( i=1 ; i<n ; i++ ){
if ( A[i]==x ) count++;
else{
if ( count ) count--;
else {
x=A[i];
count++;
}
}
}
if ( count )
for ( i=count=0 ; i<n ; i++ )
if ( A[i]==x ) count++;
if ( count>n/2 ) return x;
else return -1;
}
//***11.【2011统考真题】一个长度为L(L≥1)的升序序列S,
//处在第[L/2]个位置的数称为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+或Java语言描述算法,关键之处给出注释。
//3)说明你所设计算法的时间复杂度和空间复杂度。
//审题:中位数 第[L/2]个位置 等长升序序列 找出两个序列A和B的中位数
//思路一:先有序合并两序列,再找到中位数,时空复杂度均为O(n)
//思路二:利用已知条件,可以快速找到A,B各自中位数a,b
// 若a==b,则序列A和B的中位数为 a或b
// 若a>b ,则删去A中较大的一半,B中较小的一半,删去相同的长度
// 若a
// 循环上述过程,直到A,B都只剩1个元素,取较小的一个
// 时间复杂度:O(log2n),空间复杂度:O(1)
int M_Search1(int A[],int B[],int n){
int C[n*2];
int i=0,j=0,k=0;
while ( i<n && j<n ){
if ( A[i]<B[j] )
C[k++]=A[i++];
else
C[k++]=B[j++];
}
while ( i<n )
C[k++]=A[i++];
while ( j<n )
C[k++]=B[j++];
// printf("\n");
// for ( int i=0 ; i
return C[n-1];
}
int M_Search2(int A[],int B[],int n){
int s1=0,e1=n-1,m1;
int s2=0,e2=n-1,m2;
while ( s1!=e1 || s2!=e2 ){
m1=(s1+e1)/2;
m2=(e2+s2)/2;
if( A[m1]==B[m2] ) return A[m1];
else if( A[m1]>B[m2] ){
if ((s1+e1)%2==0)
e1=m1,s2=m2;
else
e1=m1,s2=m2+1;
}
else{
if ((s1+e1)%2==0)
s1=m1,e2=m2;
else
s1=m1+1,e2=m2;
}
}
return A[s1]<B[s2] ? A[s1] : B[s2];
}
//10.【2010统考真题】设将n(n>1)个整数存放到一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。
//将R中保存的序列循环左移p(0
//1)给出算法的基本设计思想。
//2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释。
//3)说明你所设计算法的时间复杂度和空间复杂度。
//审题:数组 n(n>1)整数 循环左移 p(0
//思路:要使(1,2,3,4,5,6,7) p=3-> (5,6,7,1,2,3,4)
// 可以先(1,2,3,4,5,6,7) -> (7,6,5,4,3,2,1) 再 ((7,6,5),(4,3,2,1)) -> ((5,6,7),(1,2,3,4))
void Reverse2(int A[],int left,int right){
int tmp,mid=(right+left)/2;
for ( int i=0 ; i<=mid-left ; i++ ){
tmp=A[left+i];
A[left+i]=A[right-i];
A[right-i]=tmp;
}
return ;
}
void Converse(int A[],int n,int p){
Reverse2(A,0,n-1);
Reverse2(A,0,p-1);
Reverse2(A,p,n-1);
}
//***9.线性表(a, a2, a3,…, an)中的元素递增有序且按顺序存储于计算机内.要求设计一个算法,
//完成用最少时间在表中查找数值为x的元素,若找到,则将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍递增有序。
//审题:线性表 递增有序 查找 数值为x的元素 与后继元素位置相交换 插入表中 仍递增有序 最少时间
//思路:对于有序序列的高效查找可以采用二分法,找到第一个大于等于x的元素
void SearchExchangeInsert(ElemType A[],ElemType x,int length){
int left=0,right=length-1,mid;
while ( left!=right ){ //二分法查找
mid=(left+right)/2;
if ( A[mid]==x ) break;
else if ( A[mid]<x ) left=mid+1;
else right=mid-1;
}
if ( A[mid]==x && mid!=length-1 ){ //找到x 与后继元素位置相交换
ElemType t=A[mid+1];
A[mid+1]=A[mid];
A[mid]=t;
}
if ( A[mid]!=x ){ //没找到x 插入表中
}
return ;
}
//***8.已知在一维数组 A[m+n]中依次存放两个线性表(a1, a2, a3,…, am)和(b1, b2,b3,…, bn)。
//试编写一个函数,将数组中两个顺序表的位置互换,即将(b,b, bs,…, b,)放在(a, az,43.…, am)的前面。
//审题:一维数组 两个顺序表 位置互换
//思路:要使(a,b,c,d,e,f,g) -> (e,f,g,a,b,c,d)
// 可以先(a,b,c,d,e,f,g) -> (g,f,e,d,c,b,a) 再 ((g,f,e),(d,c,b,a)) -> ((e,g,f),(a,b,c,d))
//需要进行三次逆置
void Reverse(ElemType A[],int left,int right){
ElemType tmp;
int mid=(right+left)/2;
for ( int i=0 ; i<=mid-left ; i++ ){
tmp=A[left+i];
A[left+i]=A[right-i];
A[right-i]=tmp;
}
return ;
}
void Exchange(ElemType A[],int m,int n){
Reverse(A,0,m+n-1);
Reverse(A,0,n-1);
Reverse(A,n,m+n-1);
}
//***7.将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表
//审题:两个有序顺序表 合并 一个新的有序顺序表 函数返回结果顺序表
//思路:按顺序不断将两表头较小元素放入新表中
bool Merge(Sqlist A,Sqlist B,Sqlist &C){
if ( A.length+B.length>MaxSize ) return false;
int i=0,j=0,k=0;
while ( i<A.length && j<B.length ){
if ( A.data[i]<B.data[j] )
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;
return true;
}
//6.从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同。
//审题:有序顺序表 删除重复的元素
//思路:顺序表有序则相同元素位置连续,保留其中一个即可
void Del_Same(Sqlist &L){
if ( L.length==0 ) { //判空并输出错误信息
printf("警告:顺序表为空\n");
return ;
}
int k=1; //记录当前是第几个不为x的元素
for ( int i=1 ; i<L.length ; i++ ){
if ( L.data[i]!=L.data[i-1] ){
L.data[k]=L.data[i];
k++;
}
}
L.length=k;
}
//5.从顺序表片删除其值在给定值s与t之间(包含s和t,要求s<1)的所有元素,
//若s或t不合理或顺序表为空,则显示出错信息并退出运行。
//审题:顺序表 删除值为s与t之间的元素 显示出错信息
//思路:与第三题类似,找到小于s或大于t的元素的位置即可
void Del_s_t2(Sqlist &L,ElemType s,ElemType t){
if ( s > t ){
printf("警告:s>t不合理\n");
return ;
}
if ( L.length==0 ) { //判空并输出错误信息
printf("警告:顺序表为空\n");
return ;
}
int k=0; //记录当前是第几个不为s与t之间的元素
for ( int i=0 ; i<L.length ; i++ ){
if ( L.data[i]<s || L.data[i]>t ){
L.data[k]=L.data[i];
k++;
}
}
L.length=k;
return ;
}
//4.从有序顺序表中删除其值在给定值s与t之间(要求s
//若s或t不合理或顺序表为空,则显示出错信息并退出运行。
//审题:有序顺序表 删除值为s与t之间的元素 显示出错信息
//思路:顺序表有序,则只需要删除一段连续空间即可
void Del_s_t(Sqlist &L,ElemType s,ElemType t){
if ( s > t ){
printf("警告:s>t不合理\n");
return ;
}
if ( L.length==0 ) { //判空并输出错误信息
printf("警告:顺序表为空\n");
return ;
}
int k=0; //记录当前是第几个不为s与t之间的元素
for ( int i=0 ; i<L.length ; i++ ){
if ( L.data[i]<s ) k++;
if ( L.data[i]>t ){
L.data[k]=L.data[i];
k++;
}
}
L.length=k;
return ;
}
//3.对长度为n的顺序表L,编写一个时间复杂度为O(n)、空间复杂度为O(1)的算法,
//该算法删除线性表中所有值为x的数据元素。
//审题:顺序表 删除值为x的元素 时间复杂度为O(n) 空间复杂度为O(1)
//思路:普通删除时间复杂度为O(n),删除m个x时间复杂度为O(n*m)不可行
//遍历一次删除所有x的同时找到所有不为x值元素所在位置
void Del_x(Sqlist &L,ElemType x){
int k=0; //记录当前是第几个不为x的元素
for ( int i=0 ; i<L.length ; i++ ){
if ( L.data[i]!=x ){
L.data[k]=L.data[i];
k++;
}
}
L.length=k;
}
//2.设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)。
//审题:顺序表 所有元素逆置 空间复杂度为O(1) 高效算法
//思路:不能借助新的数据结构存储,直接交换原有顺序表的值 每次交换两个只需要遍历一半
void Reverse(Sqlist &L){
ElemType tmp;
for ( int i=0 ; i<L.length/2 ; i++){
tmp=L.data[i];
L.data[i]=L.data[L.length-1-i];
L.data[L.length-1-i]=tmp;
}
return ;
}
//1.从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。
//空出的位置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行。
//审题:顺序表 删除 最小值元素(唯一) 返回元素值 最后一位填补 显示错误信息
//思路:传入顺序表 判空 遍历找最小值 函数与最小值类型相同 和最后一位交换值
ElemType Del_Min(Sqlist &L){
if ( L.length==0 ) { //判空并输出错误信息
printf("警告:顺序表为空\n");
return 0;
}
ElemType minn=L.data[0]; //假定0号元素值最小
int miid=0;
for ( int i=1 ; i<L.length ; i++ ){ //遍历寻找具有最小值的元素
if ( L.data[i]<minn ){
minn=L.data[i];
miid=i;
}
}
L.data[miid]=L.data[L.length-1]; //空出的位置由最后一个元素填补
L.length--; //删除最后一个元素
return minn; //由函数返回被删元素的值
}