数据结构:线性表顺序存储有关题目及代码

线性表顺序存储

一、顺序表定义

typedef struct {
    int data[MaxSize];
    int length;
}SqList;

二、顺序表题目及代码

1.从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。空出的位置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行。

/*
 * 算法思想:先判断表是否为空,如果为空返回false
 * 如果不为空,用min存储表中最小的值,k用来存储最小值的下标
 * 先令min等于表的第一个数即L.data[0]之后用min依次与表中的数进行比较,如果比min小,赋值给min,此时k++
 * 最后把min赋值给e,将最后一个元素赋值给L.data[k]
 */
bool search_min(SqList &L,int &e){
    if(L.length==0)
        return false;
    int min,k=0;
    min=L.data[0];
    for (int i = 1; i <L.length ; i++){
        if(min>L.data[i]){
            min=L.data[i];
            k++;
        }
    }
    e=min;
    L.data[k]=L.data[L.length-1];
    return true;

}

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

/*
 * 算法思想:先取mid为表中length/2,以mid为中心,第一个数和最后一个数进行逆置,第二个和倒数第二个进行逆置。。。
 * 直到下标大于mid时逆置结束
 */
void Reverse(SqList &L){
    int temp,mid=L.length/2;
    for (int i = 0; i <=mid; ++i) {
        temp=L.data[L.length-1-i];
        L.data[L.length-1-i]=L.data[i];
        L.data[i]=temp;
    }
}

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

/*
 * 算法思想:当L.data[i]=x时,k不变,i++;(相当于有两个数组),若不等于x时,k和i都向后查询
 */
void Delete_x(SqList &L,int x){
    int k=0;
    for (int i = 0; i < L.length; ++i) {
        if(L.data[i]!=x)
            L.data[k++]=L.data[i];
    }
    L.length=k;
}

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

/*
 * 算法思想:在3的基础上加一个判断条件:要删除的值是否在s和t之间
 * 若在s,t之间,则不进行赋值,不在s和t之间不进行赋值
 */
void Delete_st(SqList &L,int left,int right){
    if(left>right || L.length==0){
        printf("false");
        return;
    }
    int k=0;
    for (int i = 0; i < L.length; ++i) {
        if(L.data[i]<=left || L.data[i]>=right)
        {
            L.data[k++]=L.data[i];
        }
    }
    L.length =k;
}

5.从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同。


/ * 算法思想:新增一个空数组,顺序表中的每个数与新数组的最后一个数作比较,若不相等赋值到新的空数组中,直到遍历到最后一个数
 * 再把新的数组的值复制到顺序表中
 */
void Delete_Re(SqList &L){
    int b[MaxSize];
    int k=0;
    b[0]=L.data[0];
    for (int i = 1; i < L.length; ++i) {
        if(b[k]!=L.data[i]){
            b[++k]=L.data[i];
        }
    }
    for (int j = 0; j <=k; ++j) {
        L.data[j]=b[j];
    }
    L.length=k+1;
}

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

/*
 * 算法思想:新建一个顺序表
 * 将L和I的数进行比较,当L的数大于I的数,将I的数赋值给新的顺序表,I继续向后遍历;
 * 若L的数小于I的数,将L的数赋值给新的顺序表,L继续向后遍历;
 * 当L或者I任意一个遍历完后,将没有遍历的数向后赋值到新顺序表中
 */
SqList merge0(SqList M,SqList N){
    SqList a;
    int i=0,j=0,k=0;
    while (i<M.length && j<N.length){
        if (M.data[i]>=N.data[j]){
            a.data[k++]=N.data[j++];
        } else{
            a.data[k++]=M.data[i++];
        }
    }
    while (i<M.length){
            a.data[k++]=M.data[i++];
    }
    while (j<N.length){
        a.data[k++]=N.data[j++];
    }
    a.length=k;
    return a;
}

7.已知在一维数组 A[m + n]中依次存放两个线性表(a1,a2, …,am)和(b1, b2, b3,…, bn)。编写一个函数,将数组中两个顺序表的位置互换,即将(b1, b2, b3,…, bn)放在(a1,a2, …,am)的前面。

/*
 * 算法思想:先把前m个逆置,再把后n个逆置,最后把整体逆置
 */
void reverse1(SqList &L,int left,int right){
    int mid=(left+right)/2+1;
    int temp;
    for (int i = left; i < mid; ++i) {
        temp=L.data[right+left-i];
        L.data[right+left-i]=L.data[i];
        L.data[i]=temp;
    }
}
void reverse2(SqList &L,int m,int n){
    reverse1(L,0,m-1);
    reverse1(L,m,m+n-1);
    reverse1(L,0,m+n-1);
}

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

/*
 * 算法思想:二分查找法
 * 用mid定义为中间的数,如果x=mid,则进行交换
 * 如果不相等,进行x与mid大小的判断,x大在mid后方找,此时low=mid+1,high不变,再次算出low到high的中间值,再与mid进行比较
 * x小在mid前方找,此时low不变,high=mid-1,再次算出low到high的中间值,再与mid进行比较
 * 若找出,直接跳出循环,与后面的值进行交换
 * 当low大于high时,说明顺序表内不存在x,此时进行插入
 */
void findx(SqList &L,int x){
    int low=0,high=L.length-1,mid;
    while (low<high){
        mid=(low+high)/2;
        if(L.data[mid]==x){
            int temp;
            temp=L.data[mid+1];
            L.data[mid+1]=L.data[mid];
            L.data[mid]=temp;
            break;
        }else if(L.data[mid]>x){
            high=mid-1;
        } else{
            low=mid+1;
        }
    }
    if (low>=high){
        L.length++;
        int i;
        for ( i = L.length; i >low; --i) {
            L.data[i]=L.data[i-1];
        }
        L.data[low]=x;
    }
}

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

/*
 * 算法思想:在归并方法上进行改进(不再新建一个数组):S1和S2依次向后遍历,k记录下标
 * 当k=S1的长度时,停止查找,k就是中位数的下标
 */
int find_mid(SqList M,SqList N){
    int i=0,j=0,k=0,value;
    while (k!=M.length){
        k++;
        if(M.data[i]<N.data[j]){
            value=M.data[i];
            i++;
        } else{
                value=N.data[j];
            j++;
        }
    }
    return value;
}

11.已知一个整数序列A=(a1,a2,…,an-1),其中 0≤ai<n (0≤i<n)。若存在ap1=ap2=…=apm=x且m>n/2(0≤pk<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。【2013统考真题】

/*
 * 由题知,A数组里面的数是在0~n-1,那么可以新建一个长度为n的空数组count,其下标恰好也是0~n-1
 * 可以用count的下标来表示A数组里面每一个数,每传来A的一个数,在count对应下标的数值++,即记录A中每个数出现的次数
 * 对A遍历完成后,对count进行遍历,找里面>n/2的下标
 */
int find_main(SqList L){
    int i;
    int *count=(int *) malloc(sizeof (int)*L.length);
    for (i=0; i < L.length; ++i) {
        count[i]=0;
    }
    for (int i= 0; i< L.length; ++i) {
        count[L.data[i]]++;
    }
    for (i = 0; i < L.length; ++i) {
        if(count[i]>L.length/2){
            break;
        }
    }
    if(i==L.length){
        return -1;
    } else return i;
}

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

/*
 * 算法思想:
 * 新建一个空数组count,长度为L中最大的数值+2
 * 之后对原数组中大于等于0的数去找count中相应下标,其数值自增1,最后对数组count遍历,找出第一个值为0跳出循环
 * 此时的下标就是未出现的最小正整数
 */
int find_int(SqList L){
    int max=L.data[0];
    for (int i = 0; i < L.length; ++i) {
        if (max < L.data[i]) {
           max=L.data[i];
        }
    }
    printf("max is %d\n",max);
    int *count=(int *) malloc(sizeof (int)*(max+2));
    for (int i = 0; i < max+2; ++i) {
        count[i]=0;
    }
    for (int i = 0; i < max+2; ++i) {
        if(L.data[i]>0){
            count[L.data[i]]=1;
        }
    }
    int i;
    for (i=1; i < max+2; ++i) {
        if (count[i]==0){
            return i;
        }
    }
    return 0;
}

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

/*
 * 算法思想:写三层嵌套循环
 */
int abs(int a){
    if(a<0){
        a=-a;
    }
    return a;
}
int distance_min(SqList L,SqList J,SqList I){
    int a=0,b=0,c=0;
    for (int i = 0; i < L.length; ++i) {
        if (L.data[i] > 0) {
            a++;
        }
    }
    for (int j = 0; j <J.length ; ++j) {
            if(J.data[j]>0){
                b++;
        }
    }
    for (int f = 0; f <I.length ; ++f) {
        if(I.data[f]>0){
            c++;
        }
    }
    int d=a*b*c;
    SqList ax;
    int p=0;
    ax.length=d;
    for (int i = 0; i < ax.length; ++i) {
        ax.data[i]=0;
    }
    for (int i = 0; i < L.length; ++i) {
        if(L.data[i]>0){
            for (int j = 0; j < J.length; ++j) {
                if (J.data[j]>0){
                    for (int k = 0; k < I.length; ++k) {
                        ax.data[p++]= abs(L.data[i]-J.data[j])+ abs(L.data[i]-I.data[k])+ abs(J.data[j]-I.data[k]);

                        }

                    }
                }
            }
        }
    int min=ax.data[0];
    for (int i = 0; i < ax.length; ++i) {
       if(min>ax.data[i]){
           min=ax.data[i];
       }

    }
    return min;
}

三、递归

1、递归逆向输出顺序表

void f2(SqList L,int n){
    if (n<L.length-1){
       f2(L,n+1);
    }
    printf("%d",L.data[n]);
    return;
}

2、递归正向输出顺序表

int f3(SqList L,int n){
    if (n==L.length){
        return -1;
    }
    printf("%d",L.data[n]);
    return f3(L,n=n+1);
}

3、递归二分查找法

int DG_two(SqList L,int x,int low,int high){
    int mid=(low+high)/2;
    if (L.data[mid]==x || low>high){
        return mid;
    }
    if (x<L.data[mid]){
        high=mid;
    } else low=mid;
    return  DG_two(L,x,low,high);
}

总结

以上就是今天的所有内容

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值