各种排序相关题目的实现

Posted 枯萎的海风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了各种排序相关题目的实现相关的知识,希望对你有一定的参考价值。

1. 冒泡排序

循环n次, 每次将最大值交换到最后的一个位置

class BubbleSort {
public:
    int* bubbleSort(int* A, int n) {
        // write code here
        for (int i = 0; i != n - 1; i++){
            for (int j = 0; j != n - i - 1; j++){
                if (A[j] > A[j + 1])
                    swap(A[j], A[j + 1]);
            }
        }
        return A;
    }
};

2. 选择排序

每次从剩余部分中, 挑选出最小的值, 并与相应位置上的数值进行交换

class SelectionSort {
public:
    int* selectionSort(int* A, int n) {
        // write code here
        for (int i = 0; i != n; i++){
            int minid = i;
            for (int j = i; j != n; j++){
                if (A[j] < A[minid]){
                    minid = j;
                }
            }
            if (minid != i)
                swap(A[minid], A[i]);
        }
        return A;
    }
};

3. 插入排序

每次向已经排序的序列中插入一个值, 保证插入后的数组还是排序的

class InsertionSort {
public:
    int* insertionSort(int* A, int n) {
        // write code here
        for (int i = 0; i != n; i++){
            int tmp = A[i];
            for (int j = i - 1; j != -2; j--){
                if (j == -1){
                    A[j + 1] = tmp;
                    continue;
                }                  

                if (A[j] > tmp)
                    A[j + 1] = A[j];
                else{
                    A[j + 1] = tmp;
                    break;
                }
            }
        }

        return A;
    }
};

4. 归并排序

对两个子数组分别归并排序, 然后对这两个数组合并

class MergeSort {
public:
    int* mergeSort(int* A, int n) {
        // write code here
        if (n <= 1)
            return A;

        int lenA1 = n >> 1, lenA2 = n - (n >> 1);
        int * A1 = mergeSort(A, lenA1);
        int * A2 = mergeSort(A + lenA1, lenA2);

        // merge
        int * B = new int[n];
        int id1 = 0, id2 = 0, id = 0;
        while (id1 < lenA1 && id2 < lenA2){
            if (A1[id1] < A2[id2]){
                B[id++] = A1[id1++];
            }
            else{
                B[id++] = A2[id2++];
            }
        }

        while (id1 < lenA1){
            B[id++] = A1[id1++];
        }

        while (id2 < lenA2){
            B[id++] = A2[id2++];
        }

        for (int i = 0; i != n; i++){
            A[i] = B[i];
        }

        return A;
    }
};

5. 快速排序

先对原数据进行分割, 划分成 比 privot 大的和比 privot 小的部分, 然后对这两个部分分别进行快速排序

class QuickSort {
public:
    int* quickSort(int* A, int n) {
        // write code here
        if (n <= 1)
            return A;

        int tmp = A[0];
        int start = 0;
        int stop = n - 1;
        while (start < stop){
            while (start < stop && A[stop] >= tmp)
                stop--;

            if (start < stop)
                A[start] = A[stop];

            while (start < stop && A[start] < tmp)
                start++;

            if (start < stop)
                A[stop] = A[start];
        }
        A[stop] = tmp;

        quickSort(A, stop);
        quickSort(A + stop + 1, n - stop - 1);

        return A;
    }
};

6. 堆排序

建立一个堆, 然后对堆依次做调整

class HeapSort {
public:
    int* heapSort(int* A, int n) {
        // write code here
        for (int i = n - 1; i != -1; i--){
            modify(A, i);
            swap(A[i], A[0]);
        }
        return A;
    }

private:
    void modify(int * A, int n){
        for (int i = n; i != -1; i--){
            if (A[i] > A[i / 2])
                swap(A[i], A[i / 2]);
        }
    }
};

7. 希尔排序

实际上就是步长因子不断减小的插入排序

class ShellSort {
public:
    int* shellSort(int* A, int n) {
        // write code here
        for (int gap = n / 2; gap > 0; gap /= 2){
            // insert sort
            for (int i = gap; i != n; i++){
                int tmp = A[i];
                for (int j = i - gap; j >= -gap; j -= gap){
                    if (j < 0){
                        A[j + gap] = tmp;
                        continue;
                    }

                    if (A[j] > tmp){
                        A[j + gap] = A[j];
                    }
                    else{
                        A[j + gap] = tmp;
                        break;
                    }
                }
            }
        }

        return A;
    }
};

8. 计数排序

计算元素出现的次数, 然后排序

class CountingSort {
public:
    int* countingSort(int* A, int n) {
        // write code here
        int mymax = INT_MIN, mymin = INT_MAX;
        for (int i = 0; i != n; i++){
            if (mymax < A[i])
                mymax = A[i];
            if (mymin > A[i])
                mymin = A[i];
        }

        int size = mymax - mymin + 1;
        int * B = new int[size];
        memset(B, 0, size * sizeof(int));
        for (int i = 0; i != n; i++)
            B[A[i] - mymin]++;

        int id = 0;
        for (int i = 0; i != size; i++){
            for (int j = 0; j != B[i]; j++){
                A[id++] = i + mymin;
            }
        }
        return A;
    }
};

9. 基数排序

基数排序内部需要用到一个稳定的排序算法, 这里偷懒, 直接使用了STL 的 stable_sort

class RadixSort{
public:
    int* radixSort(int* A, int n) {
        // write code here
        using namespace std::placeholders;
        vector<int> arr(A, A + n);
        int mymax = *max_element(arr.begin(), arr.end());
        int N = 0;
        while (mymax){
            mymax /= 10;
            N++;
        }
        cout << N << endl;

        for (int i = 0; i != N; i++){  
            stable_sort(arr.begin(), arr.end(), bind(cmp, _1, _2, i));
            for_each(arr.begin(), arr.end(), [](int a){cout << a << " "; });
            cout << endl;
        }

        for (int i = 0; i != n; i++)
            A[i] = arr[i];
        return A;
    }

private:
    static bool cmp(int a, int b, int id){
        int aa = int(a / pow(10, id)) % 10;
        int bb = int(b / pow(10, id)) % 10;
        return aa < bb;
    }
};

10. 小范围排序

实际上是堆排序的一种应用

/*
已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。
给定一个int数组A,同时给定A的大小n和题意中的k,请返回排序后的数组。
*/
class ScaleSort {
public:
    vector<int> sortElement(vector<int> A, int n, int k) {
        // write code here
        vector<int>  myheap(A.begin(), A.begin() + k);
        buildHeap(myheap, k);
        for (int i = 0; i != n - k; i++){
            A[i] = myheap[0];
            myheap[0] = A[i + k];
            modifyHeap(myheap, k, 0);
        }
        for (int i = 0; i != k; i++){
            A[i + n - k] = myheap[0];
            myheap[0] = myheap[k - 1 - i];
            modifyHeap(myheap, k - i, 0);
        }
        return A;
    }

private:
    void buildHeap(vector<int> & myheap, int k){
        for (int i = k / 2; i >= 0; i--){
            modifyHeap(myheap, k, i);
        }
    }

    void modifyHeap(vector<int> & myheap, int k, int pos){
        while (true){
            int targetid = 2 * pos + 1;
            if (targetid >= k)
                break;

            if (2 * pos + 2 < k && myheap[targetid] > myheap[2 * pos + 2]){
                targetid = 2 * pos + 2;
            }

            if (myheap[pos] < myheap[targetid])
                break;

            swap(myheap[targetid], myheap[pos]);
            pos = targetid;
        }
    }

//  // 递归版本的modifyHeap
//  void modifyHeap(vector<int> & myheap, int k, int pos){
//      int targetid = 2 * pos + 1;
//      if (targetid >= k)
//          return;
//
//      if (2 * pos + 2 < k && myheap[targetid] > myheap[2 * pos + 2]){
//          targetid = 2 * pos + 2;
//      }
//
//      if (myheap[pos] < myheap[targetid])
//          return;
//
//      swap(myheap[targetid], myheap[pos]);
//      modifyHeap(myheap, k, targetid);
//  }
};

11. 重复值判断

/*
请设计一个高效算法,判断数组中是否有重复值。必须保证额外空间复杂度为O(1)。
给定一个int数组A及它的大小n,请返回它是否有重复值。
*/
class Checker {
public:
    bool checkDuplicate(vector<int> & a, int n) {
        // write code here
        buildHeap(a, n);
        for (int i = 0; i != n; i++){
            swap(a[n - i - 1], a[0]);
            modifyHeap(a, n - i - 1, 0);
        }

        for (int i = 0; i != n; i++){
            if (i > 0 && a[i - 1] == a[i])
                return true;
        }
        return false;
    }

private:
    void buildHeap(vector<int> & myheap, int k){
        for (int i = k / 2; i >= 0; i--){
            modifyHeap(myheap, k, i);
        }
    }

    void modifyHeap(vector<int> & myheap, int k, int pos){
        while (true){
            int targetid = 2 * pos + 1;
            if (targetid >= k)
                break;

            if (2 * pos + 2 < k && myheap[targetid] > myheap[2 * pos + 2]){
                targetid = 2 * pos + 2;
            }

            if (myheap[pos] < myheap[targetid])
                break;

            swap(myheap[targetid], myheap[pos]);
            pos = targetid;
        }
    }

};

12. 有序数合并

从数组的尾部开始操作

/* 
有两个从小到大排序以后的数组A和B,其中A的末端有足够的缓冲空容纳B。请编写一个方法,将B合并入A并排序。
给定两个有序int数组A和B,A中的缓冲空用0填充,同时给定A和B的真实大小int n和int m,请返回合并后的数组。
*/
class Merge {
public:
    int* mergeAB(int* A, int* B, int n, int m) {
        // write code here
        int ia = n - 1, ib = m - 1, id = n + m - 1;
        while (ib >= 0){
            if (ia >= 0){
                if (A[ia] >= B[ib])
                    A[id--] = A[ia--];
                else
                    A[id--] = B[ib--];
            }
            else
                A[id--] = B[ib--];
        }
        return A;
    }
};

13. 三色排序

荷兰国旗问题, 三个指针区分三个数据范围{0}{1}{2}

class ThreeColor {
public:
    vector<int> sortThreeColor(vector<int> A, int n) {
        // write code here
        int low = 0, high = n - 1, cur = 0;
        while (cur <= high){
            if (A[cur] == 1)
                cur++;
            else if (A[cur] == 0){
                if (cur != low)
                    swap(A[cur], A[low]);
                cur++;
                low++;
            }
            else if (A[cur] == 2){
                swap(A[cur], A[high]);
                high--;
            }
        }

        return A;
    }
};

14. 有序矩阵查找

典型的杨氏矩阵查找问题, 从左上角入手

/*
现在有一个行和列都排好序的矩阵,请设计一个高效算法,快速查找矩阵中是否含有值x。
给定一个int矩阵mat,同时给定矩阵大小nxm及待查找的数x,请返回一个bool值,代表矩阵中是否存在x。所有矩阵中数字及x均为int范围内整数。保证n和m均小于等于1000。
*/
class Finder {
public:
    bool findX(vector<vector<int> > mat, int n, int m, int x) {
        // write code here
        int i = 0, j = m - 1;
        while (true){
            if (i >= n || j < 0)
                return false;

            if (mat[i][j] == x)
                return true;
            else if (mat[i][j] > x)
                j--;
            else
                i++;
        }
        return false;
    }
};

15. 最短子数组

从左边开始找第一个下降的项位置, 从右边开始找第一个上升的项的位置

/*
对于一个数组,请设计一个高效算法计算需要排序的最短子数组的长度。
给定一个int数组A和数组的大小n,请返回一个二元组,代表所求序列的长度。(原序列位置从0开始标号,若原序列有序,返回0)。保证A中元素均为正整数。
*/
class Subsequence {
public:
    int shortestSubsequence(vector<int> A, int n) {
        // write code here
        int left = 0, right = 1;
        int mymax;
        for (int i = 0; i != n; i++){
            if (i == 0){
                mymax = A[0];
            }
            else{
                if (mymax <= A[i]){
                    mymax = A[i];
                }
                else{
                    left = i;
                }
            }
        }

        int mymin;
        for (int i = n - 1; i != -1; i--){
            if (i == n - 1){
                mymin = A[n - 1];
            }
            else{
                if (mymin >= A[i]){
                    mymin = A[i];
                }
                else{
                    right = i;
                }
            }
        }

        return left - right + 1;
    }
};

16. 相邻两数最大差值

利用桶排序的思想 (鸽巢原理)

/*
有一个整形数组A,请设计一个复杂度为O(n)的算法,算出排序后相邻两数的最大差值。
给定一个int数组A和A的大小n,请返回最大的差值。保证数组元素多于1个。
*/
class Gap {
public:
    int maxGap(vector<int> A, int n) {
        // write code here
        int mymax = INT_MIN, mymin = INT_MAX;
        for (int i = 0; i != n; i++){
            if (A[i] > mymax)
                mymax = A[i];
            if (A[i] < mymin)
                mymin = A[i];
        }

        double gap = (mymax - mymin + 0.001) * 1.0 / (n + 1);
        vector<vector<int>> bucks(n + 1, vector<int>{INT_MIN, INT_MAX, 0});
        for (int i = 0; i != n; i++){
            int id = (A[i] - mymin) / gap;
            bucks[id][0] = max(bucks[id][0], A[i]);
            bucks[id][1] = min(bucks[id][1], A[i]);
            bucks[id][2]++;
        }

        int maxgap = 0;
        int id = 0;
        while (id < n){
            while (!bucks[id][2])
                id++;

            int low = bucks[id][0];
            id++;
            while (!bucks[id][2])
                id++;

            int high = bucks[id][1];
            int tmp = high - low;
            maxgap = max(maxgap, tmp);
        }

        return maxgap;
    }
};

以上是关于各种排序相关题目的实现的主要内容,如果未能解决你的问题,请参考以下文章

第九次作业

AJAX相关JS代码片段和部分浏览器模型

排序杂谈

LeetCode 堆(优先级队列) 相关题目

201621123054《Java程序设计》第九周学习总结

201621123048《Java程序设计》第九周学习总结