排序算法

1)插入排序(稳定)。从第二个元素开始,依次从剩余元素中选择一个,插入到前面有序的子序列中。在元素数量较少时,比较高效。

public static void insertSort(int[] nums){
        if ( nums == null ){
            return;
        }
        int len = nums.length;
        int tmp, j;
        for(int i = 1; i < len; ++i){
            tmp = nums[i];
            j = i - 1;
            while( j >= 0 && tmp < nums[j]){
                nums[j + 1] = nums[j];
                j--;
            }
            nums[j + 1] = tmp;
        }
    }

 

2)快速排序(不稳定,平均时间复杂度O(nlogn))

public void quickSort(int[] a, int low, int high) {
        if (low < high) {
            int location = partition(a,low,high);
            quickSort(a, low, location - 1);
            quickSort(a, location + 1, high);
        }
    }
    
    public int partition(int[] a, int left, int right) {
        if (left < right) {
            int pivot = a[left];
            while(left < right){
                while (left < right && a[right] >= pivot) {
                    right--;
                }
                a[left] = a[right];
                while (left < right && a[left] <= pivot) {
                    left++;
                }
                a[right] = a[left];
            }
            a[left] = pivot;
        }
        return left;
    }

 

3)归并排序(稳定,时间复杂度O(nlogn))

public void mergeSort(int[] a, int low, int high) {
        if (low < high) {
            int mid = (low + high) / 2;
            mergeSort(a, low, mid);
            mergeSort(a, mid + 1, high);
            merge(a, low, mid, high);
        }
    }
    
    public void merge(int[] a, int left, int mid, int right) {
        if (left < right){
            int len = right - left + 1;
            int[] b = new int[len];
            int i = left, j = mid + 1, k = 0;
            while(i <= mid && j <= right){
                if (a[i] <= a[j]) {
                    b[k++] = a[i++];
                } else {
                    b[k++] = a[j++];
                }
            }
            while (i <= mid) {
                b[k++] = a[i++];
            }
            while (j <= right) {
                b[k++] = a[j++];
            }
            for (int l = 0; l < k; ++l){
                a[l + left] = b[l];
            }
        }
    }

 

4)堆排序(不稳定,时间复杂度O(nlogn))

    /**
     * 堆排序
     * @param a
     */
    public void heapSort(int[] a) {
        if (a == null || a.length == 0) {
            return;
        }
        int len = a.length;
        for (int i = 0; i < len; ++i){
            //createMaxHeap(a,len - 1 - i); //从小到大排序
            createMinHeap(a, len - 1 - i); // 从大到小排序
            swap(a, 0, len - 1 - i);
        }
    }
    
    // 建堆以及调整堆
    public void createMaxHeap(int[] a, int lastIndex) {
        for(int j = (lastIndex - 1) / 2; j >= 0; --j){ // 从最后一个非叶子结点开始调整
            int k = j;
            
            // 调整以k结点为根的子树
            while(2 * k + 1 <= lastIndex){
                // 找到孩子结点中的值较大者
                int biggerIndex = 2 * k + 1; // 至少有一个左孩子
                if (biggerIndex < lastIndex) { // 存在右孩子
                    if (a[biggerIndex] < a[biggerIndex + 1]) {
                        biggerIndex++;
                    }
                }
                
                if (a[k] < a[biggerIndex]) { // 需要调整子树
                    swap(a, k, biggerIndex);
                    k = biggerIndex; // 循环调整
                } else { // 不需要调整该子树,break。继续从下一个非叶子结点开始调整
                    break;
                }
            }
        }
    }
    
    // 建堆以及调整堆
    public void createMinHeap(int[] a, int lastIndex) {
        for(int j = (lastIndex - 1) / 2; j >= 0; --j){ // 从最后一个非叶子结点开始调整
            int k = j;
            
            // 调整以k结点为根的子树
            while(2 * k + 1 <= lastIndex){
                // 找到孩子结点中的值较小值
                int lessIndex = 2 * k + 1; // 至少有一个左孩子
                if (lessIndex < lastIndex) { // 存在右孩子
                    if (a[lessIndex + 1] < a[lessIndex]) {
                        lessIndex++;
                    }
                }
                
                if (a[k] > a[lessIndex]) { // 需要调整子树
                    swap(a, k, lessIndex);
                    k = lessIndex; // 循环调整
                } else { // 不需要调整该子树,break。继续从下一个非叶子结点开始调整
                    break;
                }
            }
        }
    }    
    
    public void swap(int[] a, int i, int j) {
        int tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
    }

 

5)计数排序、基数排序、桶排序。

    上述1-4是最常见和最常用的几种排序算法。但是,在大数据量排序时,依然具有较大的时间和空间复杂度。因此,需要寻求新的排序方式。

    a)若了解排序对象的已知限制情况,可以使用计数排序。比如对成绩、年龄、日期等具有上下限的数据。

    b)若对大数据量求前100名、前10名、排行榜等,可以采用降维的方法,对数据进行一次扫描即可得到所求结果。

          比如求前10大,可以用10个空间,放入前10个,从大到小排好序。依次遍历剩余的数据,若其比最小者大,则交换两者,对新的10个元素重新排序;若其比较小者还小,则指针继续向下遍历。

    c)桶排序:将大数据划分为n个桶,对各个桶中的数据进行排序,然后再将各个桶中的有序数据汇总排序,得到最终的有序序列。

          比如:对考生试卷得分排序。低于60分的一个桶,60-80一个桶,80-100一个桶。

6)Tim sort?

7)判断一个链表是否是双向循环链表?

posted @ 2017-12-20 20:09  江湖凶险  阅读(182)  评论(0编辑  收藏  举报