• 七种常见的排序算法


    原理请参考《算法导论》

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

    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));//可采用任何改编的稳定排序算法
    }

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

  • 相关阅读:
    Knight Moves
    Knight Moves
    Catch him
    Catch him
    Linux查看硬件信息以及驱动设备的命令
    23种设计模式彩图
    Android开发指南-框架主题-安全和许可
    Android启动组件的三种主流及若干非主流方式
    ACE在Linux下编译安装
    void及void指针含义的深刻解析
  • 原文地址:https://www.cnblogs.com/dalgleish/p/8847285.html
Copyright © 2020-2023  润新知