Sort Integers II整数排序(二)

 

问题描述:给定一个整数数组,按照升序排序,使用快速排序归并排序堆排序或任何时间代价O(nlogn)的算法。

Given an integer array, sort it in ascending order in place. Use quick sort, merge sort, heap sort or any O(nlogn) algorithm.

参考:殷建平、徐云、王刚、刘晓光、苏明、邹恒明、王宏志译,Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein著,《算法导论》原书第3版,第2、6、7章。

思路:

(一)归并排序

采用分而治之的策略,将原数组等分为两个小数组,分别对小数组排好序,然后归并(组合)成升序排列的大数组。归并过程中,额外存放了两个小数组,选取两个数组相比之下,当前最小的单元,存入原数组的相应位置。

代码如下:

class Solution {
public:
    /**
     * @param A: an integer array
     * @return: nothing
     */
    void sortIntegers2(vector<int> &A) {
        // write your code here
        mergeSortIntegers(A,0,A.size()-1);
    }
    void mergeSortIntegers(vector<int> &A, int p, int r) {
        if (p<r) {
            int q = (p+r)/2;
            mergeSortIntegers(A,p,q);
            mergeSortIntegers(A,q+1,r);
            merge(A,p,q,r);
        }
    }
    void merge(vector<int> &A, int p, int q, int r) {
        int n1 = q-p+1;
        int n2 = r-q;
        vector<int> L, R;
        int i;
        for (i = 0; i < n1; i++) {
            L.push_back(A[p+i]);
        }
        for (i = 0; i < n2; i++) {
            R.push_back(A[q+1+i]);
        }
        L.push_back(INT_MAX);
        R.push_back(INT_MAX);
        int j = 0, k;
        i = 0;
        for (k = p; k <= r; k++) {
            if (L[i] < R[j]) {
                A[k] = L[i];
                i++;
            } else {
                A[k] = R[j];
                j++;
            }
        }
    }
};

(二)堆排序

思路:根据原数组创建最大堆(完全二叉树,父节点取值必定大于子节点的取值),数组元素个数为n。将堆的根节点与原数组的最后位置的元素互换,此时数组最后位置存放了整个数组中的最大值(根据最大堆的性质);最大堆元素个数减1(即为n-1),由于根节点被置换,可能不满足最大堆的性质,需重新处理下,使包含n-1个元素的数组符合最大堆性质。依此,逐渐置换最大堆根节点到数组中的合适位置。

代码如下:

class Solution {
public:
    /**
     * @param A: an integer array
     * @return: nothing
     */
    void sortIntegers2(vector<int> &A) {
        // write your code here
        heapSort(A);
    }
    int heapSize = 0; // global variable
    void heapSort(vector<int> &A) {
        //global int 
        heapSize = A.size();
        buildMaxHeap(A);
        for (int i = A.size()-1; i >= 1; i--) {
            // put current heap's root node(0) to the back of the sorted vector(i)
            // heap size - 1
            int t = A[i];
            A[i] = A[0];
            A[0] = t;
            heapSize--;
            maxHeapify(A,0);
        }
    }
    void buildMaxHeap(vector<int> &A) {
        // build max heap bottom up
        // Max heap has heapSize/2 inner nodes.
        for (int i = heapSize/2-1; i >= 0; i-- ) {
            maxHeapify(A,i);
        }
    }
    void maxHeapify(vector<int> &A, int i) {
        // compare current node with its children. 
        int l = LEFT(i);
        int r = RIGHT(i);
        int largest = i;
        if (l <= heapSize-1 && A[l] > A[i]) largest = l; //index-1
        if (r <= heapSize-1 && A[r] > A[largest]) largest = r; //compare with largest
        if (largest != i) {
            int t = A[largest];
            A[largest] = A[i];
            A[i] = t;
            maxHeapify(A,largest);
        }
    }
    int LEFT(int i) {
        // left child
        return 2*i+1;
    }
    int RIGHT(int i) {
        // right child
        return 2*(i+1);
    }
};

(三)快速排序

思路:采用分而治之的策略。需要对数组作切分,比如目标是排序数组A从下标p到下标r位置的元素,那需要找到一个中间位置q,满足A[q]大于所有A[p,q-1]的元素,并且A[q]小于所有A[q+1,r]的元素。分别对两个子数组排序。子数组排序还是递归进行。难点在找到合适的分割点,从待排序数组中选择一个元素x(可任意选择),遍历所有数组中的元素,如果小于x,则安置在数组的前面[p,q-1]范围内,从下标p开始递增安置。最后将小于x的子数组的下一个位置,安排成元素x(将x从原位置调换过来)。

代码如下:

class Solution {
public:
    /**
     * @param A: an integer array
     * @return: nothing
     */
    int heapSize = 0; // global variable
    
    void sortIntegers2(vector<int> &A) {
        // write your code here
        quickSort(A,0,A.size()-1);
    }
    
    void quickSort(vector<int> &A,int p, int r) {
        if (p<r) {
            int q = partition(A,p,r);
            quickSort(A,p,q-1);
            quickSort(A,q+1,r);
        }
    }
    int partition(vector<int> &A, int p, int r) {
        int x = A[r];
        int i = p-1;
        int t;
        for (int j = p; j <= r-1; j++) {
            if (A[j]<x) {
                i++;
                t = A[j];
                A[j] = A[i];
                A[i] = t;
            }
        }
        t = A[i+1];
        A[i+1] = x;
        A[r] = t;
        return i+1;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值