顺序表的编程题及完整代码(顺序表逆置、删除、合并、查找等)

顺序表的存储类型描述

#define MaxSize 100
typedef struct Sqlist{
	int data[MaxSize];
	int length;
}Sqlist, 


顺序表逆置

将循序表L中的所有元素逆置

问题描述:
将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)。

算法思想:
扫描顺序表L的前半部分元素,对于元素L.data[i](0<=i<L.length/2),将其与后半部分对应元素L.data[L.length-1-i]进行交换。

实现代码:

//逆置
void Reverse(Sqlist &L){
    for(int i=0; i<L.length/2; i++){
//         swap(L.data[i],L.data[L.length-i-1]);  //可直接用swap函数或自己写交换操作
        int temp = L.data[i];
        L.data[i] = L.data[L.length-1-i];
        L.data[L.length-1-i] = temp;
    }
}


将两个顺序表的位置互换

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

算法思想:
设 p=(a1,a2, … ,am), q=(b1,b2, … ,bn)。那么(pq)-1 = (q-1)(p-1) = (bn, … ,b2,b1)(am, … ,a2,a1),即将数组A中的元素全部逆置,然后再分别将q 和 p 单独逆置即可。

实现代码:

void Reverse(Sqlist &L, int left, int right){
    if(left>right || right>L.length){
        return;
    }
    int mid = (right-left)/2;
    for(int i=0; i<mid; i++){
         swap(L.data[left+i],L.data[right-i]);
    }
}
void Exchange(Sqlist &L, int m, int n){
    Reverse(L,0,m+n-1);  //逆置L
    Reverse(L,0,n-1);  //逆置q
    Reverse(L,n,m+n-1); //逆置p
}


删除操作

删除顺序表L中所有值为x的数据元素

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

算法思想:
解法一:
用k记录顺序表L中不等于x的元素个数,边扫描边统计k,将不等于x的元素向前移动k个位置,最后修改L的长度。
解法二:
用k记录顺序表L中等于x的元素个数,边扫描边统计k,将不等于x的元素向前移动k个位置,最后修改L的长度。

实现代码:

//解法一
void DeleteX(Sqlist &L, int 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;  //顺序表L的长度等于k
}
//解法二
void DeleteX2(Sqlist &L, int x){
    int k=0;     //记录值等于x的元素的个数
    int i=0;
    while(i<L.length){
        if(L.data[i] == x){
            k++;
        }else{
            L.data[i-k] = L.data[i];
        }
        i++;
    }
    L.length -= k;
}


删除有序顺序表L中所有值重复的元素

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

算法思想:
注意是有序顺序表,值相同的元素一定在连续的位置上,故初始时将第一个元素视为非重复的有序表,然后依次判断后面的元素是否与前面非重复有序表的最后一个元素相同,如果相同则继续向后判断,若不同则插入到前面的有序表的最后,直至判断到队尾。

实现代码:

//删除有序表L中所有值重复的元素
void DeleteSame(Sqlist &L){
    if(L.length==0)return;
    int i=0,j=1;  //j为工作指针
    while(j<L.length){
        if(L.data[i] != L.data[j]){ //查找下一个与上个元素值不同的元素
            L.data[++i] = L.data[j]; //将该元素添加到前面的非重复有序表的最后
        }
        j++;
    }
    L.length = i+1;
}


合并操作

将两个有序顺序表合并成一个新的有序顺序表

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

算法思想:
首先,按顺序不断取下两个顺序表中表头较小的结点存入新的顺序表中。然后,看哪个表还有剩余,将剩下的部分添加到新的顺序表后面。

实现代码:

//合并两个有序表
void UnionSqlist(Sqlist &A, Sqlist &B, Sqlist &C){
    if(A.length+B.length > C.maxSize)return;
    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;
}


查找操作

找两个等长升序序列的中位数

问题描述:
一个长度为L的升序序列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的中位数。

算法思想:
分别求升序序列A和B的中位数,设为a和b。
若a=b,则即为所求中位数。
若a<b,舍弃A中较小的一半和B中较大的一半,要求舍弃的长度相等。
若a>b,舍弃A中较大的一半和B中较小的一半,要求舍弃的长度相等。
在保留的两个升序序列中,重复上述过程直到两个序列中均只含一个元素为止,较小者即为所求的中位数。

int Searchmid(Sqlist A, Sqlist B, int n){
    int s1=0,d1=n-1,m1; //序列A的首位数、末位数、中位数
    int s2=0,d2=n-1,m2; //序列B的首位数、末位数、中位数
    while(s1!=d1 || s2!=d2){
        m1=(s1+d1)/2;
        m2=(s2+d2)/2;
        if(A.data[m1] == B.data[m2])
            return A.data[m1];
        if(A.data[m1] < B.data[m2]){
            if((s1+d1)%2 == 0){ //元素个数为奇数
                s1=m1; //舍弃A中间点以前的部分且保留中间点
                d2=m2; //舍弃B中间点以后的部分且保留中间点
            }else{   //元素个数为偶数
                s1=m1+1;  //舍弃A中间点以及中间点以前的部分
                d2=m2;  //舍弃B中间点以后部分且保留中间点
            }
        }else{
            if((s2+d2)%2 == 0){ //元素个数为奇数
                d1=m1;
                s2=m2;
            }else{
                d1=m1;
                s2=m2+1;
            }
        }
    }
    return A.data[s1]<B.data[s2] ? A.data[s1] : B.data[s2];
}


找出数组中未出现的最小正整数

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

算法思想:
采用空间换时间的办法。从A[0]开始遍历A,若0<A[i]<=n,则令B[A[i] - 1] = 1,否则不做操作。B[n]为标记数组,用来记录A中是否出现了1~n的正整数,B[0]对应正整数1,B[n-1]对应正整数n。
对A遍历结束后,遍历B,找到第一个满足B[i] == 0的下标,并输出i+1;若B[i]全不为0,则返回i+1(跳出循环时i=n,即 i+1=n+1)。

实现代码:

int findMissMin(int *A, int n){
    int *B; //标记数组
    B = (int *)malloc(sizeof(int)*n); //分配空间
    memset(B,0,sizeof(int)*n); //赋初始值为0
    int i;
    for(i=0; i<n; i++){
        if(A[i]>0 && A[i]<=n)
            B[A[i]-1]=1;
    }
    for(i=0; i<n; i++){
        if(B[i]==0)break; //找到之后跳出循环
    }
    return i+1; 
}

[注]关于memset函数:
是一个初始化函数,作用是将某一块内存中的全部设置为指定的值。

void *memset(void *s, int c, size_t n); 
s指向要填充的内存块。
c是要被设置的值。
n是要被设置该值的字符数。
返回类型是一个指向存储区s的指针。

更详细的memset用法请参考文章memset的用法详解


说明

以上是我整理的一些关于顺序表上的一些题目及实现代码,以后如果遇到顺序表的问题会持续更新哦~

  • 3
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值