原理请参考《算法导论》

一、插入式排序算法实现:

void insertion_sort(int *A, int length) {
    int i, key;
    for (int j = 1; j < length; j++) {//从第二个开始判断,保证前面有序
        key = A[j];
        i = j - 1;
        while (i >= 0 && A[i] > key) {
            A[i + 1] = A[i];
            i--;
        }
        A[i + 1] = key;//插入
    }
}

二、递归实现分治,merge函数实现合并算法实现:

void merge(int *A, int p, int q, int r) {//q属于[q, r]
    //分治保证L, R数组是有序的
    int n1, n2, *L, *R, i, j;
    n1 = q - p + 1;//[p, q]
    n2 = r - q;//(q, r]
    L = new int[n1];
    R = new int[n2];
    for (i = 0; i < n1; i++)
        L[i] = A[p + i];
    for (j = 0; j < n2; j++)
        R[j] = A[q + 1 + j];
    i = j = 0;
    for (int k = p; k <= r; k++) {
        if (j == n2)//任意一边选完了,直接进去
            A[k] = L[i++];
        else if (i == n1)
            A[k] = R[j++];
        else {
            if (L[i] < R[j])
                A[k] = L[i++];
            else
                A[k] = R[j++];
        }
    }
    delete[] L;
    delete[] R;
}
void merge_sort(int *A, int p, int r) {//p=0, r=n-1
    if (p < r) {
        //递归实现分治,和二叉树一样,p<r自动实现过滤没有用的节点
        merge_sort(A, p, (p + r) / 2);
        merge_sort(A, (p + r) / 2 + 1, r);
        merge(A, p, (p + r) / 2, r);//此函数实现合并
    }
}

三、冒泡算法实现:

void bubble_sort(int *A, int length) {
    int mid;
    for (int i = 0; i < length; i++) {
        for (int j = length - 1; j > i; j--)
            if (A[j] < A[j - 1]) {//双双相比
                mid = A[j];
                A[j] = A[j - 1];
                A[j - 1] = mid;
            }
    }
}

四、堆栈排序算法实现(实质上是数组和二叉树之间的映射):

定义数组: A[0]表示堆栈大小,即数组元素个数;所以数组中数据的下标是1开始到n

元素交换:

void swap(int &a, int &b) {
    int mid = a;
    a = b;
    b = mid;
}

父子节点获取:

int parent(int i) {//子节点
    return i / 2;
}
int left(int i) {//i 此时是父节点的index
    return i * 2;
}

int right(int i) {
    return i * 2 + 1;
}

针对指定父节点开始,进行堆栈最大化,从沿着不满足的子节点继续:

void max_heapify(int *A, int i) {//i是父节点
    int l, r,  largest;
    l = left(i);
    r = right(i);
    if (l <= A[0] && A[l] > A[i])//左节点和父节点比较
        largest = l;
    else
        largest = i;
    if (r <= A[0] && A[r] > A[largest])
        largest = r;
    if (largest != i) {//若父节点不是最大
        swap(A[i], A[largest]);
        max_heapify(A, largest);
    }
}

从最高处的父节点至最底处的根节点,每一个父节点都要进行堆栈最大化:

void build_max_heapify(int *A) {
    //从最高处的父节点开始(相对于根节点)
    for (int i = A[0] / 2; i >= 1; i--)
        max_heapify(A, i);
}

把已经是堆栈最大化(但可能有部分节点不满足左子叶小于右子叶,但不影响排序)的数组进行以下操作

1. 根节点和最高处的子节点交换

2. 缩小堆栈大小

3. 从根节点开始,再次进行堆栈最大化

void sort_max_heapify(int *A) {
    //满足最大堆时,从把最高处末子节点和根节点交换,再进行最大堆构建,并且缩小堆大小
    int heapsizeback = A[0];
    build_max_heapify(A);
    for (int i = A[0]; i >= 2; i--) {
        swap(A[1], A[i]);
        A[0]--;
        max_heapify(A, 1);//始终从根节点开始构造
    }
    A[0] = heapsizeback;
}

 五、快速排序算法实现:

patrition函数(把比特定值小的放到左边,把比特定值大的放右边,然后把特定值放中间的分割线处)

int patrition(int *A, int p, int r) {
    int x = A[r], i = p;
    for (int j = p; j < r; j++) {
        if (A[j] < x) {//
            swap(A[j], A[i]);
            i++;
        }
    }
    swap(A[i], A[r]);//特定值放分界处
    return i;
}

主函数

void quick_sort(int *A, int p, int r) {//p=0, r=n-1
    if (p < r) {
        int q = patrition(A, p, r);//i左边全是小于特定值,i+1到j全是大于特定值
        quick_sort(A, p, q - 1);//跳过特定值
        quick_sort(A, q + 1, r);
    }
}

 六、stooge快速排序算法实现:

void stooge_sort(int *A, int p, int r) {//p=0, r=n-1
    int k;
    if (A[p] > A[r])
        swap(A[p], A[r]);
    if (p + 1 == r) return;//已经到了最后一个则停止
    k = (r - p + 1) / 3;
    stooge_sort(A, p, r - k);//前2/3
    stooge_sort(A, p + k, r);//后2/3
    stooge_sort(A, p, r - k);//再次前2/3
}

 七、基数排序算法实现:

这种算法一定是建立在另一种稳定算法的基础上,按位比较。这里随便找了一个stooge快速排序,并且改编。

注意:此算法针对等长的数据很精确,变长的数据不稳定。并没有仔细研究这个算法,初步推测是跟改编的算法有关。

在数据中,找出最大位数

int radix_maximum(int *A, int length) {
    int max = A[0], d=1;
    for (int i = 1; i < length; i++)
        if (A[i] > max)
            max = A[i];
    while (max % (int)pow(10, d) != max) d++;
    return d;
}

改编stooge算法,使其满足基数排序

void radix_stooge_sort(int *A, int p, int r, int d) {
    int k;
    if (A[r] % d == A[r] && A[p] % d != A[p])//前大后小
        swap(A[p], A[r]);
    else if (A[p] % d == A[p] && A[r] % d != A[r]) {//前小后长
        //什么都不用做
    }
    else if (A[p] % d == A[p] && A[r] % d == A[r]) {//两者都不满足
        //什么都不做
    }
    else if ((A[p] / d % 10) == (A[r] / d % 10)) {
        //再多判断一位,radix采用任何算法的相等处,需要特殊处理
        if (d != 1 && A[p] / (d / 10) % 10 > (A[r] / (d / 10) % 10))
            swap(A[p], A[r]);
    }
    else if ((A[p] / d % 10) > (A[r] / d % 10))
        swap(A[p], A[r]);
    if (p + 1 == r) return;//已经到了最后一个则停止
    k = (r - p + 1) / 3;
    radix_stooge_sort(A, p, r - k, d);//前2/3
    radix_stooge_sort(A, p + k, r, d);//后2/3
    radix_stooge_sort(A, p, r - k, d);//再次前2/3
}

 

基数排序实现(必须建立在另一种稳定算法上)

void  radix_sort(int *A, int length) {
    for (int d = 0; d < radix_maximum(A, length); d++) 
        radix_stooge_sort(A, 0, length - 1, pow(10, d));//可采用任何改编的稳定排序算法
}

 

 

所有代码均经过测试,结果正确。

posted on 2018-04-15 13:45  dalgleish  阅读(223)  评论(0编辑  收藏  举报