(笔记)第九讲 排序(上)

219 阅读2分钟

简单排序(冒泡、插入),希尔排序,堆排序,归并排序

第九讲 排序(上) - 浙江大学

9.1 简单排序

image-20201026222433424

image-20201026220039474

image-20201026220423944

package bobo;

import java.util.Arrays;

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
        Arrays.sort(arr);

        System.out.println(Arrays.toString(arr));
        BubbleSort bubbleSort = new BubbleSort();
        bubbleSort.sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public void sort(int[] arr) {
        int N = arr.length;
        for (int i = N - 1; i >= 0; i--) {
            int flag = 0;
            for (int j = 0; j < i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    flag = 1;
                }
            }
            if (flag == 0) break;
        }
    }
}

image-20201026221912811

package bobo;

import java.util.Arrays;

public class SimpleSort {
    public static void main(String[] args) {
        int[] arr = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
        SimpleSort simpleSort = new SimpleSort();
        simpleSort.sort(arr, arr.length);
        System.out.println(Arrays.toString(arr));
    }

    private void sort(int[] arr, int N) {
        int i = 0;
        int j = 0;
        for (i = 0; i < N; i++) {
            if (i == 0) continue; // 第一次摸牌不用排序
            int temp = arr[i]; // 先记住牌的大小
            for (j = i; j > 0 && arr[j - 1] > temp; j--) { // 从后往前看已知的排,看看应该排在哪里
                arr[j] = arr[j - 1]; // 往后移出空位
            }
            arr[j] = temp; // 新牌落位
        }
    }
}

9.2 希尔排序

image-20201027195320157

image-20201027195006188

image-20201027195013767

package bobo;

import java.util.Arrays;

public class ShellSort {
    public static void main(String[] args) {
        ShellSort shellSort = new ShellSort();
        int[] arr = {10, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1};
        shellSort.sort(arr, arr.length);
        System.out.println(Arrays.toString(arr));
    }
    private void sort (int[] arr, int N) {
        int D = 0; // D间隔

        for (D = N / 2; D > 0; D /= 2) { /* 希尔增量序列 */
            int i = 0;
            int j = 0;
            for (i = 0; i < N; i++) { // 【注意】i++。也就是说,虽然间隔着D在排序,但并不是完整排完一组才排下一组
                if (i < D) continue; // 第一次摸牌不用排序 // 【注意】在插入排序的基础上,改1为D、改-1为-D
                int temp = arr[i]; // 先记住牌的大小
                for (j = i; j >= D && arr[j - D] > temp; j -= D) { // 从后往前看已知的排,看看应该排在哪里
                    arr[j] = arr[j - D]; // 往后移出空位
                }
                arr[j] = temp; // 新牌落位
            }
        }
    }
}

希尔排序的形象展示过程可以参考:希尔排序 | 算法必看系列九

9.3 堆排序

image-20201027221644313

选择排序

package bobo;

import java.util.Arrays;

public class SelectionSort {
    public static void main(String[] args) {
        int[] arr = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
        SelectionSort selectionSort = new SelectionSort();
        selectionSort.sort(arr, arr.length);
        System.out.println(Arrays.toString(arr));
    }

    private void sort(int[] arr, int N) {
        for (int i = 0; i < N; i++) {
            // 每一趟,找到最小元所在的位置pos
            int MinPosition = scanForMin(arr, i, N - 1);
            // 把最小元放到有序部分的最后面(第i次会放在第i个位置)
            int temp = arr[i];
            arr[i] = arr[MinPosition];
            arr[MinPosition] = temp;
        }
    }
    private int scanForMin (int[] arr, int start, int end) {
        int pos = start;
        for (int i = start + 1; i <= end; i++) { // 注意起始位置都是可达的
            if (arr[i] < arr[pos]) pos = i;
        }
        return pos; // 返回最小元所在的位置pos
    }
}

堆排序

思路1

调成最小堆,然后依次弹出,得到的就是从小到大排序

思路2

调成最大堆,然后把堆顶放到最后,固定住,堆的大小-1

image-20201027211140723

image-20201027211905088

注:PercDown(A, i, N)的含义是:

下滤:将大小为N的数组A中,以A->Data[i]为根的子堆,调整为最大堆

A: 堆 (用数组表示)

i: 下标

N: 堆的规模 (数组的大小)

基础:建立最大堆 (将数组调整成最大堆) (C)

/*----------- 建造最大堆 -----------*/
void PercDown( MaxHeap H, int p )
{ /* 【√】下滤:将H中以H->Data[p]为根的子堆调整为最大堆 */
    int Parent, Child;
    ElementType X;

    X = H->Data[p]; /* 取出根结点存放的值 */
    for( Parent=p; Parent*2<=H->Size; Parent=Child ) {
        Child = Parent * 2;
        if( (Child!=H->Size) && (H->Data[Child]<H->Data[Child+1]) )
            Child++;  /* Child指向左右子结点的较大者 */
        if( X >= H->Data[Child] ) break; /* 找到了合适位置 */
        else  /* 下滤X */
            H->Data[Parent] = H->Data[Child];
    }
    H->Data[Parent] = X;
}

void BuildHeap( MaxHeap H )
{ /* 调整H->Data[]中的元素,使满足最大堆的有序性  */
  /* 这里假设所有H->Size个元素已经存在H->Data[]中 */

    int i;

    /* 【√】从最后一个结点的父节点开始,到根结点1 */
    for( i = H->Size/2; i>0; i-- )
        PercDown( H, i );
}

堆排序 (Java)

package bobo;

import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Queue;

public class HeapSort {
    private void sort(int[] arr, int N) {
        Queue<Integer> heap = new PriorityQueue<>(); // 用Java的优先队列建立堆
        for (int i = 0; i < N; i++) {
            heap.add(arr[i]); // 默认是小顶堆
        }
        for (int i = 0; i < N; i++) {
            arr[i] = heap.remove(); // 逐个从堆顶弹出
        }
    }
    public static void main(String[] args) {
        int[] arr = {10, 9, 8, 7, 7, 6, 5, 4, 3, 2, 1};
        HeapSort heapSort = new HeapSort();
        heapSort.sort(arr, arr.length);
        System.out.println(Arrays.toString(arr));
    }
}

Java直接调用优先队列PriorityQueue的话,很方便。

使用PriorityQueue - 廖雪峰

但是注意到,JavaPriorityQueue默认是一个小顶堆,如果要大顶堆的话,可以重写Comparator方法,或者是用负值

final int DEFAULT_INITIAL_CAPACITY = 10;
Queue<Integer> heap = new PriorityQueue<>(DEFAULT_INITIAL_CAPACITY, new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2 - o1;
    }
}); // 用Java的优先队列建立堆

image-20201027221934830

9.4 归并排序

image-20201029222919016