数据结构强化之快速排序

数据结构强化

1.快速排序算法

1.1 2011统考真题42

42.一个长度为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)说明你所设计算法的时间复杂度和空间复杂度。

运行代码

#include<stdio.h>
int A[5] = {11, 13, 15, 17, 19};
int B[5] = {2, 4, 6, 8, 20};
// 寻找枢轴
int partition(int A[],int L,int R){
    int mid = A[L];
    while (L<R){
      while (A[R]>=mid && L<R) R--;
      A[L] = A[R];
      while (A[L]<=mid && L<R) L++;
      A[R] = A[L];
    }
    A[L] = mid;
    return L;
}
// 循环快排
void QSort(int A[],int L,int R){
    if(L>=R) return;
    int M = partition(A,L,R);
    QSort(A,L,M-1); // 左半部分快排
    QSort(A,M+1,R); // 右半部分快排
}
// 打印数组信息
void Print(int A[],int length){
    for (int i = 0; i < length; ++i) {
        printf(" %d",A[i]);
    }
}
// 寻找中位数
int func(int A[],int M,int B[],int N){
    // 两数组合并
    int C[M+N];
    for (int i = 0; i < M; ++i) {
        C[i]= A[i];
    }
    for (int i = 0; i < N; ++i) {
        C[i+M] = B[i];
    }
    // 对合并后数组快速排序
    QSort(C,0,M+N-1);
    printf("序列C:");
    Print(C,10);
    // 找到中间元素
    return C[(N+M-1)/2];
}
int main() {
    printf("序列A:");
    Print(A,5);
    printf("\n");
    printf("序列B:");
    Print(B,5);
    printf("\n");
    printf("\n两个序列A和B的中位数是:%d",func(A,5,B,5));
}

输出结果

序列A: 11 13 15 17 19
序列B: 2 4 6 8 20
序列C: 2 4 6 8 11 13 15 17 19 20
两个序列A和B的中位数是:11

1.2 2013统考真题41

41.已知一个整数序列A=(a0,a1,……,an-1),其中ai大于等于0,小于n(i大于等于0小于n)。若存在apl=ap2=……=apm=x且m>n/2(Pk大于等于0小于m,k大于等于1小于等于m),则称x为A的主元素。例如A=(0,5,5,3,5,7,5,5),则5为主元素;又如A=(0,5,5,3,5,15,7),则A中没有主元素。假设A中的n个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出A的主元素。若存在主元素,则输出该元素;否则输出-1。要求:
(1)给出算法的基本设计思想。
(2) 根据设计思想,采用 C、C++或 Java 语言描述算法,关键之处给出注释
(3)说明你所设计算法的时间复杂度和空间复杂度。

运行代码

#include<stdio.h>

int A[8] = {0, 5, 5, 3, 5, 7, 5, 5};
int B[8] = {0, 5, 5, 3, 5, 1, 5, 7};

int partition(int A[], int L, int R) {
    int mid = A[L];
    while (L < R) {
        while (A[R] >= mid && L < R) R--;
        A[L] = A[R];
        while (A[L] <= mid && L < R) L++;
        A[R] = A[L];
    }
    A[L] = mid;
    return L;
}

void QSort(int A[], int L, int R) {
    if (L >= R) return;
    int M = partition(A, L, R);
    QSort(A, L, M - 1); // 左半部分快排
    QSort(A, M + 1, R); // 右半部分快排
}

void Print(int A[], int length) {
    for (int i = 0; i < length; ++i) {
        printf(" %d", A[i]);
    }
}

int func(int A[], int n) {
    QSort(A, 0, n - 1);
    int x = A[n / 2];
    int count = 0;
    // 左半部分主元素个数累加
    for (int i = n / 2 - 1; i >= 0; --i)
        if (A[i] == x)
            count++;
    // 右半部分主元素个数累计
    for (int i = n / 2; i <= n - 1; ++i)
        if (A[i] == x)
            count++;
    // 比较主元素与数组长度一半
    if (count > n / 2) return x;
    else return -1;
}

int main() {
    printf("数组A:");
    Print(A, 8);
    printf("\n");
    printf("数组B:");
    Print(B, 8);
    printf("\n");
    printf("数组A的主元素为:%d", func(A, 8));
    printf("\n");
    printf("数组B的主元素为:%d", func(B, 8));
}

输出结果

数组A: 0 5 5 3 5 7 5 5
数组B: 0 5 5 3 5 1 5 7
数组A的主元素为:5
数组B的主元素为:-1

1.3 2018统考真题41

41.给定一个含n(n大于等于1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。例如,数组{-5,3,2,3}中未出现的最小正整数是1; 数组{1,2,3}中未出现的最小正整数是4。要求:
(1)给出算法的基本设计思想。
(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释(3)说明你所设计算法的时间复杂度和空间复杂度。

运行代码

#include<stdio.h>

int A[5] = {-5,1,2,3,4};
int B[5] = {-5,4,7,3,2};
int C[5] = {-5,-4,-7,-3,-2};

int partition(int A[], int L, int R) {
    int mid = A[L];
    while (L < R) {
        while (A[R] >= mid && L < R) R--;
        A[L] = A[R];
        while (A[L] <= mid && L < R) L++;
        A[R] = A[L];
    }
    A[L] = mid;
    return L;
}

void QSort(int A[], int L, int R) {
    if (L >= R) return;
    int M = partition(A, L, R);
    QSort(A, L, M - 1); // 左半部分快排
    QSort(A, M + 1, R); // 右半部分快排
}

void Print(int A[], int length) {
    for (int i = 0; i < length; ++i) {
        printf(" %d", A[i]);
    }
}

int func(int A[], int n) {
    QSort(A, 0, n - 1);
    int m = -1;
    for (int i = 0; i < n; i++) {
        if(A[i]>0){
            m = i;
            break;
        }
    }
    // 数组值全为负值
    if(m == -1) return 1;
    // 数组中不含有值为1的数
    if(A[m] != 1) return 1;
    // 检查数组相邻差值
    for (m= m+1; m < n; m++)
        // 数组相邻差值大于1
        if(A[m]-A[m-1]>1)
            // 较小元素加一
            return A[m-1]+1;
    //  数组相邻差值均等于1 最大元素加1
    return  A[n-1]+1;
}

int main() {
    printf("数组A:");
    Print(A, 5);
    printf("\n");
    printf("数组B:");
    Print(B, 5);
    printf("\n");
    printf("数组C:");
    Print(C, 5);
    printf("\n");
    printf("数组A中未出现的最小正整数是:%d", func(A, 5));
    printf("\n");
    printf("数组B中未出现的最小正整数是:%d", func(B, 5));
    printf("\n");
    printf("数组C中未出现的最小正整数是:%d", func(C, 5));
    printf("\n");

}

输出结果

数组A: -5 1 2 3 4
数组B: -5 4 7 3 2
数组C: -5 -4 -7 -3 -2
数组A中未出现的最小正整数是:5
数组B中未出现的最小正整数是:1
数组C中未出现的最小正整数是:1

1.4 2016统考真题43

43.已知由n(n>=2)个正整数构成的集合A={ak|0<=k<n},将其划分为两个不相交的子集A1和A2,元素个数分别是n1和n2,A1和A2中元素之和分别为S1和S2。设计一个尽可能高效的划分算法,满足 |n1-n2|最小且|S1-S2|最大。要求:
(1)给出算法的基本设计思想。
(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。
(3)说明你所设计算法的平均时间复杂度和空间复杂度。

运行代码

#include<stdio.h>
int A[5] = {1, 13, 5, 21, 19};
// 寻找枢轴
int partition(int A[],int L,int R){
    int mid = A[L];
    while (L<R){
        while (A[R]>=mid && L<R) R--;
        A[L] = A[R];
        while (A[L]<=mid && L<R) L++;
        A[R] = A[L];
    }
    A[L] = mid;
    return L;
}
// 循环快排
void QSort(int A[],int L,int R){
    if(L>=R) return;
    int M = partition(A,L,R);
    QSort(A,L,M-1); // 左半部分快排
    QSort(A,M+1,R); // 右半部分快排
}
// 打印数组信息
void Print(int A[],int length){
    for (int i = 0; i < length; ++i) {
        printf(" %d",A[i]);
    }
}
// 寻找中位数
int func(int A[],int n){
    QSort(A,0,n-1);
}
int main() {
    printf("未排序:");
    Print(A,5);
    printf("\n");
    printf("排序后:");
    func(A,5);
    Print(A,5);
    // 集合A1为A[0]~A[n/2-1]
    // 集合A2为A[n/2]~A[n-1]
    // min |n1-n2| max |s1-s2|
}

输出结果

未排序: 1 13 5 21 19
排序后: 1 5 13 19 21

2.快速排序算法划分思想

2.1 例题1

试编写一个算法,使之能够在数组L[1...n]中找出第k小的元素 (即从小到大排序后处于第k个位置的元素)。

运行代码

#include<stdio.h>
int A[5] = {1, 13, 5, 21, 19};
// 寻找枢轴
int partition(int A[],int L,int R){
    int mid = A[L];
    while (L<R){
        while (A[R]>=mid && L<R) R--;
        A[L] = A[R];
        while (A[L]<=mid && L<R) L++;
        A[R] = A[L];
    }
    A[L] = mid;
    return L;
}

// 打印数组信息
void Print(int A[],int length){
    for (int i = 0; i < length; ++i) {
        printf(" %d",A[i]);
    }
}

int func(int L[],int n,int k){
    int left = 1,right = n,M=0;
    while (1){
        M = partition(L,left,right);
        if(M==k) break;
        else if(M>k) right=M-1;
        else if(M<k) left = M+1;
    }
    return L[k];
}

int main() {
    printf("数组为:");
    Print(A,5);
    printf("\n");
    printf("第3小的元素为%d",func(A,5,3));
}

输出结果

数组为: 1 13 5 21 19
第3小的元素为13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值