数据结构线性表部分习题(二)

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

void DelElms41(Sqlist &L, int s, int t) {
    int k = 0;
    if (s > t || L.length == 0) {
        printf("false");
        return;
    }//任意一个满足都不会运行程序
    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;
}

void DelElms42(Sqlist &L, int s, int t) {
    int i = 0;
    int k = 0;
    if (s > t || L.length == 0) {
        printf("false");
        return;
    }//任意一个满足都不会运行程序
    while (i < L.length) {
        if (L.data[i] >= s && L.data[i] <= t) {
            k++;
        } else {
            L.data[i - k] = L.data[i];//当前元素前移k个位置
        }
        i++;
    }
    L.length = L.length - k;
}

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

思路:题目重点是"有序"顺序表,说明若其值重复的元素必相邻,遍历顺序表,从第二位元素开始,每次都与前驱元素进行比较判断,若重复则标记
void Del_Re(Sqlist &L) {
    int i = 1;
    int k = 0;//保存重复元素个数
    for (i; i < L.length; i++) {
        if (L.data[i] == L.data[i - 1]) {
            k++;
        } else {
            L.data[i - k] = L.data[i];
        }
    }
    L.length = L.length - k;
}

7.将两个有序顺序表合并为一个新的线性表,并由函数返回新的顺序表。

思路:归并算法
Sqlist merge(Sqlist A, Sqlist B,Sqlist &L) {
    int i = 0;
    int j = 0;
    int k = 0;
    while (A.length + B.length <= Maxside && i < A.length && j < B.length) {
        if (A.data[i] <= B.data[j]) {
            L.data[k++] = A.data[i++];
        } else{
            L.data[k++] = B.data[j++];
        }
    }
    while(i<A.length){
        L.data[k++]=A.data[i++];
    }
    while(j<B.length){
        L.data[k++]=B.data[j++];
    }
    L.length = k;
    return L;
}

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

思路:三次逆转实现,前两次为数组里面的两个线性表各自逆转,第三次为整体逆转。
void reverse2(Sqlist &L, int start, int end) {
    int temp = 0;
    if (start > end) {
        return;
    }
    for (int i = start, k = 0; i < (start + end) / 2 + 1; k++) { //⚠️此处有"+1",假若忽略此条件,当start+end=1时,不会产生互换。
        temp = L.data[i];
        L.data[i] = L.data[end - k];
        L.data[end - k] = temp;
        i++;
    }
}

void test08(){
    Sqlist L{{1, 2, 3, 44, 11, 22, 33},7};//L.length别忘记
    reverse2(L, 0, 2);
    reverse2(L, 4, 6);
    reverse2(L, 0, 6);
    for (int i = 0; i < L.length; i++) {
        printf(" %d", L.data[i]);
    }
}

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

思路:运用折半查找优化时间复杂度。
void FindValue(Sqlist &L, int x) {
    int low = 0;
    int mid = 0;
    int high = L.length - 1;
    int temp;
    while (low <= high) {
        mid = (low + high) / 2;
        if (L.data[mid] == x) {
            break;
        } else if (L.data[mid] > x) {
            high = mid - 1;
        } else {
            low = mid + 1;
        }
    }
    if (L.data[mid] == x && mid != L.length-1) {
        temp = L.data[mid];
        L.data[mid] = L.data[mid + 1];
        L.data[mid + 1] = temp;
    }
    if (low > high) {
        for (int i = L.length - 1; i > high; i--) {
            L.data[i + 1] = L.data[i];
        }
        L.data[low] = x;
        L.length++;
    }
}

10.设将n(n>1)个整数存放到一维数组R中。设计一个在时间和空间两方面都将可能高效的算法。将R中保存的序列循环左移p(0<p<n)个位置。

思路:把被移部分和剩下部分视为两个数组,实现两个数组整体的逆值即可,即(A1,A2)转变为(A2,A1),其中A1是被移部分的数组,A2是剩下部分的数组。
void reverse3(Sqlist &L, int start, int p) {
    int temp = 0;
    for (int i = start, k = 0; i < (start + p) / 2 + 1; k++) { //⚠️此处有"+1",假若忽略此条件,当start+p=1时,不会产生互换。
        temp = L.data[i];
        L.data[i] = L.data[p - k];
        L.data[p - k] = temp;
        i++;
    }
}

void test10() {
    int p;
    scanf("%d",&p);
    Sqlist L = {{1, 2, 3, 4, 5}, 5};
    reverse3(L, 0, p-1);
    reverse3(L, p, L.length-1);
    reverse3(L, 0, L.length-1);
    for (int i = 0; i < L.length; i++) {
        printf(" %d", L.data[i]);
    }
}

11.试设计一个在空间和时间上尽可能高效的算法,找出两个升序序列A和B的中位数。

思路:利用归并算法,合并两个升序序列,并找到新序列的中位数。
double midAB(Sqlist &A, Sqlist &B) {
    Sqlist L = {};
    int i = 0;
    int j = 0;
    int k = 0;
    double mid = 0;
    while (A.length + B.length <= Maxside && i < A.length && j < B.length) {
        if (A.data[i] <= B.data[j]) {
            L.data[k++] = A.data[i++];
        } else {
            L.data[k++] = B.data[j++];
        }
    }
    while (i < A.length) {
        L.data[k++] = A.data[i++];
    }
    while (j < B.length) {
        L.data[k++] = B.data[j++];
    }
    L.length = k;
    if (k % 2 == 1) { //判断奇数序列
        mid = double(L.data[(k + 1) / 2 - 1]);
    } else if (k % 2 == 0) { //判断偶数序列
        mid = double((L.data[k / 2 - 1] + L.data[k / 2])) / 2;
    }
//    for (int i = 0; i < L.length; i++) {
//        printf(" %d", L.data[i]);
//    }
    return mid;
}

void test11() {
    Sqlist A = {{4, 5, 6}, 3};
    Sqlist B = {{1, 2, 3}, 3};
    printf(" %0.2f", midAB(A, B));
}

12.请设计一个尽可能高效的算法,找出A的主元素(元素出现次数大于元素总数的一半)。若存在则输出主元素,不存在则输出-1。

int findMainValue(Sqlist &L, int n) {
    int *count = (int *) malloc(sizeof(int) * n);
    for (int i = 0; i < n; ++i) {
        count[i] = 0;//初始化线性表
    }
    for (int i = 0; i < L.length; i++) {
        count[L.data[i]]++;//映射数组,遍历原数组,通过count在新数组的对应位置上统计元素出现次数,此时新数组的索引为原数组的元素值
    }
    int max = 0, maxIndex = 0;
    for (int i = 1; i < n; i++) {
        if (count[i] > max) { //找出count值最大(即相同元素出现的最多次数)
            max = count[i];
            maxIndex = i;
        }
    }
    if (max > L.length / 2) //主元素的判断
        return maxIndex;
    else
        return -1;
}

void test12() {
    Sqlist A{{5, 8, 7, 7, 7, 8, 8, 8, 8}, 9};
    Sqlist B{{0, 5, 5, 3, 5, 7, 5}, 7};

    printf("%d", findMainValue(A, 9));
//    findMainValue(B,7);
}

13.给定一个含n(n>=1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小整数。

思路:与上题类似,用映射关系来解决问题。
int Find_NMin_Int(Sqlist &L, int n) { //n>=MaxL.data[i]+2
    int mint = 0;
    int *count = (int *) malloc(sizeof(int) * n);
    for (int i = 0; i < n; ++i) {
        count[i] = 0;//初始化线性表
    }
    for (int i = 0; i < L.length; i++) {
        if (L.data[i] < 0) {
            L.data[i] == 0; //把L中所有小于0的数改成0
        }
        count[L.data[i]]++;//映射数组,遍历原数组,通过count在新数组的对应位置上统计元素出现次数,此时新数组的索引为原数组的元素值
    }
    for (int i = 1; i < n; ++i){
        if(count[i]==0){ //找出出现次数为0的最小正整数,并输出。
            mint = i;
            break;
        }

    }

        return mint;
}

void test13(){
    Sqlist L={{-5, 3, 2, 3},4};
    Sqlist A={{1, 2, 3},3};
    printf("%d", Find_NMin_Int(A,5));
}

14.定义三元组(a,b,c)(a,b,c,均为正数)的距离D = |a-b|+|b-c|+|c-a|。给定3个非空正数集合S1、S2和S3,按升序分别存储在3个数组中。请设计一个尽可能高效的算法,计算并输出所有可能的三元组(a,b,c)的最小距离。

思路:三重for循环找出符合条件的三元组。
#define MAX 0xffffff

int abs(int value) {    //构造绝对值函数
    if (value < 0)return -value;
    else return value;
}

int distance(int i, int j, int k) { //计算距离
    int dist = abs(i - j) + abs(j - k) + abs(k - i);
    return dist;
}

void Min_distance(Sqlist S1, Sqlist S2, Sqlist S3) {
    int min = MAX;
    int res[3]; //用于存放三元组
    for (int i = 0; i < S1.length; i++) {
        for (int j = 0; j < S2.length; j++) {
            for (int k = 0; k < S3.length; k++) {
                if (min > distance(S1.data[i], S2.data[j], S3.data[k])) { 
                    res[0] = S1.data[i];
                    res[1] = S2.data[j];
                    res[2] = S3.data[k];
                    min = distance(S1.data[i], S2.data[j], S3.data[k]);
                }
            }
        }
    }
    printf("(%d,%d,%d)", res[0], res[1], res[2]);
}

void test14() {
    Sqlist L{{-1, 0, 9}, 3};
    Sqlist A{{-25, -10, 10, 11}, 4};
    Sqlist B{{2, 9, 17, 30, 41}, 5};
    Min_distance(L, A, B);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值