数据结构研究之五 高级排序

1.归并排序

a.步骤提要:将原有数组分割平分成两个数组,然后分别排序。将排好序的局部数组整合成一个数组,然后递归执行此过程 

b.过程:

//
// Created by 叶子 on 2018/1/27.
// 归并排序
//

#include "iostream"
using namespace std;
#define MAX 500000
#define SENTINEL 20000000;

int L[MAX/2+2],R[MAX/2+2];
int cnt;

void merge(int A[],int n,int left,int mid,int right) {
    int n1 = mid - left;
    int n2 = right - mid;
    for (int i = 0; i < n1; i++) L[i] = A[left + i];
    for (int i = 0; i < n2; i++) R[i] = A[mid + i];
    L[n1] = R[n2] = SENTINEL;
    int i = 0, j = 0;
    for (int k = left; k < right; k++) {
        cnt++;
        if (L[i] <= R[j]) {
            A[k] = L[i++];
        } else {
            A[k] = R[j++];
        }
    }
}

void mergeSort(int a[], int n, int left, int right) {
    if (left + 1 < right) {
        int mid = (left + right) / 2;
        mergeSort(a, n, left, mid);
        mergeSort(a, n, mid, right);
        merge(a, n, left, mid, right);
    }
}


int main(){
    int A[MAX],n,i;
    cnt = 0;

    cin >> n;
    for ( i = 0 ; i < n ; i ++) cin >> A[i];

    mergeSort(A,n,0,n);

    for ( i = 0 ; i < n ; i ++){
        if ( i ) cout << " ";
        cout << A[i];
    }
    cout << endl;

    cout << cnt <<endl;
}

备注:归并排序虽然高效且稳定,但是它在处理的过程当中,除了用于保存输入数据的数组之外,还需要临时占用一部分内存空间。

2.分割:
题目:将指定的数组按标记值M分割成为小于M的部分和大于M的部分
注意点:分割会交换不相邻的元素,用于排序时要注意
代码:
//
// Created by 叶子 on 2018/1/27.
// 分割
//

#include <stdio.h>
#define MAX 100000

int A[MAX],n;

int partition(int p,int r){
    int x,i,j,t;
    x = A[r];
    i = p - 1;
    for ( j = p ; j < r ; j ++){
        if ( A[j] <= x){
            i ++;
            t = A[i];A[i] = A[j];A[j] = t;
        }
    }
    t = A[i+1];A[i+1]= A[r];A[r] = t;
    return i+1;
}

int main(){
    int i,q;

    scanf("%d",&n);
    for ( i = 0 ; i < n ; i ++) scanf("%d",&A[i]);

    q = partition(0,n-1);

    for ( i = 0 ; i < n ; i ++){
        if ( i ) printf(" ");
        if ( i == q) printf("[");
        printf("%d",A[i]);
        if ( i == q) printf("]");
    }
    printf("\n");

    return 0;

}

3.快速排序:
a.题目:将指定的扑克在考虑花色和点数的情况下按升序排列,另外判断这些输入的数字和输出的顺序是否一致
b.步骤:
1)以数组的最末尾的值为标准值“分割”数组
2)将分割好的数组执行快速排序
3)合并,然后递归执行这三步
c.注意点:要提高效率,可以在每次分割时以需要分割的数组的“中间值”为标准值
d.代码:
//
// Created by 叶子 on 2018/1/27.
// 快速排序与归并排序的比较
//

#include <stdio.h>
#define MAX 100000
#define SENTINEL 2000000000

struct Card {
    char suit;
    int value;
};

struct Card L[MAX / 2 + 2],R[MAX / 2 + 2];

void merge(struct Card A[],int n ,int left,int mid,int right){
    int i,j,k;
    int n1 = mid - left;
    int n2 = right - mid;
    for ( i = 0 ; i < n1 ; i ++) L[i] = A[left+i];
    for ( i = 0 ; i < n2 ; i ++) R[i] = A[mid + i];
    L[n1].value = R[n2].value = SENTINEL;
    i = j = 0;
    for ( k = left; k < right ; k ++){
        if ( L[i].value <= R[j].value){
            A[k] = L[i++];
        }else{
            A[k] = R[j++];
        }
    }
}

void mergeSort(struct Card A[],int n ,int left,int right){
    int mid;
    if ( left + 1 < right){
        mid = (left + right) /2 ;
        mergeSort(A,n,left,mid);
        mergeSort(A,n,mid,right);
        merge(A,n,left,mid,right);
    }
}

int partition(struct Card A[],int n ,int p ,int r){
    int i,j;
    struct Card t,x;
    x = A[r];
    i = p -1;
    for ( j = p;j < r ; j ++){
        if ( A[j].value <= x.value){
            i ++;
            t = A[i]; A[i] = A[j];A[j] = t;
        }
    }
    t = A[i+1];A[i+1] = A[r];A[r] = t;
    return i+1;
}

void quickSort(struct Card A[],int n,int p ,int r){
    int q;
    if ( p < r){
        q = partition(A,n,p,r);
        quickSort(A,n,p,q-1);
        quickSort(A,n,q+1,r);
    }
}

int main(){
    int n,i,v;
    struct Card A[MAX],B[MAX];
    char S[10];
    int stable = 1;

    scanf("%d",&n);

    for ( i = 0 ; i < n ; i ++){
        scanf("%s %d",S,&v);
        A[i].suit = B[i].suit = S[0];
        A[i].value = B[i].value = v;
    }

    mergeSort(A,n,0,n);
    quickSort(B,n,0,n-1);

    for ( i = 0 ; i < n ; i ++){
        if ( A[i].suit != B[i].suit ) stable = 0;
    }

    if ( stable == 1) printf("Stable\n");
    else printf("Not stable\n");
    for ( i = 0 ; i < n ; i ++){
        printf("%c %d\n",B[i].suit,B[i].value);
    }

    return 0;
}

4.计数排序:
a.简介:它能在线性时间(O(n+k))内对包含n个元素的数组进行排序,其中数组无素均大于等于0且小于k
b.详述:对于输入数组A的各元素A(j)进行排序时,将小于等于A(j)的元素数记录在计数数组C中,然后根据C中的数值计算A(j)在输出数组B中的位置。考虑到存在多个相等元素的情况,我们还需要在输出元素A(j)【加入B】之后修正计数用的C(A(j))
c.注意:其运行所需要的时间及内存空间也与A(j)的最大值成正比
d.代码:

//
// Created by 叶子 on 2018/1/28.
// 计数排序

#include "stdio.h"
#include "stdlib.h"
#define MAX 200001
#define VMAX 10000

int main(){
    int A[VMAX + 1],B[VMAX + 1],C[VMAX + 1], n,i,j;
    scanf("%d",&n);

    for ( i = 0 ; i <= VMAX ; i ++) C[i] = 0;

    for ( i = 0 ; i < n ; i ++){
        scanf("%hu",&A[i+1]);
        C[A[i+1]] ++;
    }

    for ( i = 1 ; i <= VMAX ; i ++) C[i] = C[i] + C[i-1];

    for ( j = 1 ; j <= n ; j ++){
        B[C[A[j]]] = A[j];
        C[A[j]] --;
    }

    for ( i = 1 ; i <=n ; i ++){
        if ( i > 1)  printf (" ");
        printf ("%d",B[i]);
    }
    printf("\n");

    return 0;
}

5.使用标准库排序:
a.定义:使用标准库里的sort

b.代码:

//
// Created by 叶子 on 2018/1/28.
// 用C++内置函数排序
//


#include "iostream"
#include "vector"
#include "algorithm"
using namespace std;

int main(){
    int n;
    vector<int> v;

    cin >> n;
    for ( int i = 0 ; i < n ; i ++){
        int x; cin >> x;
        v.push_back(x);
    }
    sort(v.begin(),v.end());

    for ( int i = 0 ; i < v.size() ; i ++){
        cout << v[i] << " ";
    }
    cout << endl;

    return 0;
}


6.最小成本排序:

a.题目:求给指定的数组进行排序的最小交换次数

b.解析:需要考虑“借整体最小元素”与“不借整体最小元素”两种情况

c.代码:

//
// Created by 叶子 on 2018/1/28.
// 最小成本统计
//

#include "iostream"
#include "algorithm"
using namespace std;
static const int MAX = 1000;
static const int VMAX = 10000;

int n,A[MAX],s;
int B[MAX],T[VMAX + 1];

int solve(){
    int ans = 0;

    bool V[MAX];
    int v;
    for ( int i = 0 ; i < n ; i ++){
        B[i] = A[i];
        V[i] = false;
    }

    sort(B,B+n);

    for ( int i = 0 ; i < n ; i ++) T[B[i]] = i ;
    for ( int i = 0 ; i < n ; i ++){
        if (V[i] ) continue;
        int cur = i ;
        int S = 0;
        int m = VMAX;
        int an = 0 ;
        while ( 1 ) {
            V[cur] = true;
            an ++;
            v = A[cur];
            m = min (m,v);
            S += v;
            cur = T[v];
            if ( V[cur] ) break;
        }
        ans += min(S+(an-2) * m,m+S+(an+1)*s);
    }
    return ans;
}

int main(){
    cin >> n;
    s = VMAX;
    for ( int i = 0 ; i < n ; i ++){
        cin >> A[i];
        s = min(s,A[i]);
    }
    int ans = solve();
    cout << ans << endl;

    return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值