【恋上数据结构与算法 第二季】【01】排序


持续学习&持续更新中…

学习态度:脚踏实地


排序

初识排序

在这里插入图片描述

十大排序算法

在这里插入图片描述

排序算法的稳定性

在这里插入图片描述

原地算法

在这里插入图片描述

常见的递推式与复杂度

在这里插入图片描述

抽象基类Sort

简单实现

public abstract class Sort<E extends Comparable<E>>  {

    private Comparator<E> comparator;
    protected E[] array;
    protected int cmpCount; // 比较次数
    protected int swapCount; // 交换次数

    public Sort() {
        this(null);
    }

    public Sort(Comparator<E> comparator) {
        this.comparator = comparator;
    }

    public void sort(E[] array) {
        if (null == array || array.length < 2) {
            return;
        }
        this.array = array;
        sort();
        System.out.println(this.getClass().getSimpleName() + " 比较次数:" + cmpCount + " 交换次数:" + swapCount);
    }

    protected int compare(E e1, E e2) {
        cmpCount++;
        return comparator == null ? e1.compareTo(e2) : comparator.compare(e1, e2);
    }

    protected void swap(int index1, int index2) {
        E temp = array[index1];
        array[index1] = array[index2];
        array[index2] = temp;

        swapCount++;
    }

    protected abstract void sort();

}

完善实现


public abstract class Sort<T extends Comparable<T>> implements Comparable<Sort<T>> {

    protected T[] array;
    private int cmpCount;
    private int swapCount;
    private long time;
    private final DecimalFormat fmt = new DecimalFormat("#.00");

    public void sort(T[] array) {
        if (array == null || array.length < 2) return;

        this.array = array;

        long begin = System.currentTimeMillis();
        sort();
        time = System.currentTimeMillis() - begin;
    }

    @Override
    public int compareTo(Sort<T> o) {
        int result = (int) (time - o.time);
        if (result != 0) return result;
        result = cmpCount - o.cmpCount;
        if (result != 0) return result;
        return swapCount - o.swapCount;
    }

    protected abstract void sort();

    /*
     * 返回值等于0,代表 array[i1] == array[i2]
     * 返回值小于0,代表 array[i1] < array[i2]
     * 返回值大于0,代表 array[i1] > array[i2]
     */
    protected int cmp(int i1, int i2) {
        cmpCount++;
        return array[i1].compareTo(array[i2]);
    }

    protected int cmp(T v1, T v2) {
        cmpCount++;
        return v1.compareTo(v2);
    }

    protected void swap(int i1, int i2) {
        swapCount++;
        T tmp = array[i1];
        array[i1] = array[i2];
        array[i2] = tmp;
    }

    @Override
    public String toString() {
        String timeStr = "耗时:" + (time / 1000.0) + "s(" + time + "ms)";
        String compareCountStr = "比较:" + numberString(cmpCount);
        String swapCountStr = "交换:" + numberString(swapCount);
        String stableStr = "稳定性:" + isStable();
        return "【" + getClass().getSimpleName() + "】\n"
                + stableStr + " \t"
                + timeStr + " \t"
                + compareCountStr + "\t "
                + swapCountStr + "\n"
                + "------------------------------------------------------------------";

    }

    private String numberString(int number) {
        if (number < 10000) return "" + number;
        if (number < 100000000) return fmt.format(number / 10000.0) + "万";
        return fmt.format(number / 100000000.0) + "亿";
    }

    private boolean isStable() {
        Student[] students = new Student[20];
        for (int i = 0; i < students.length; i++) {
            students[i] = new Student(i * 10, 10);
        }
        sort((T[]) students);
        for (int i = 1; i < students.length; i++) {
            int score = students[i].score;
            int prevScore = students[i - 1].score;
            if (score != prevScore + 10) return false;
        }
        return true;
    }
}

冒泡排序

在这里插入图片描述

	// 旧写法(不推荐使用了)
    private static void method1(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) { // n - 1 个循环
            for (int j = 0; j < arr.length - 1 - i; j++) { // n - 1 次比较
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

优化1

在这里插入图片描述

    private static void method(int[] arr) {
        for (int end = arr.length; end > 0; end--) {
            boolean sorted = true;
            for (int begin = 1; begin < end; begin++) {
                if (arr[begin - 1] > arr[begin]) {
                    int temp = arr[begin];
                    arr[begin] = arr[begin - 1];
                    arr[begin - 1] = temp;
                    sorted = false;
                }
            }
            if (sorted) break;
        }
    }

优化2

在这里插入图片描述

    public static void sort3(Integer[] arr) {
        for (int end = arr.length - 1; end > 0; end--) {
            // sortedIndex在元素已经排好序时有用
            // 如果有序的话,初始值赋为1,1-0 <= 0,可以让循环结束
            
            // 如果有序的话,初始值赋为1,1经过内层循环后不会改变,1-0 <= 0,就可以让循环结束
            // 如果不有序的话,sortedIndex会记录最后一次交换的位置
            int sortedIndex = 1;
            for (int begin = 1; begin <= end; begin++) {
                if (arr[begin - 1] > arr[begin]) {
                    int temp = arr[begin - 1];
                    arr[begin - 1] = arr[begin];
                    arr[begin] = temp;
                    sortedIndex = begin;
                }
            }
            end = sortedIndex;
        }
    }

重构后:

    @Override
    protected void sort() {
        for (int end = array.length - 1; end > 0; end--) {
            int sortedIndex = 1;
            for (int begin = 1; begin <= end; begin++) {
                if (compare(array[begin - 1], array[begin]) > 0) {
                    swap(begin - 1, begin);
                    sortedIndex = begin;
                }
            }
            end = sortedIndex;
        }
    }

选择排序

在这里插入图片描述

在这里插入图片描述

	public static void methodMax(Integer[] arr) {
        for (int end = arr.length; end > 0; end--) {
            int maxIndex = 0;
            for (int begin = 1; begin < end; begin++) {
                if (arr[begin] > arr[maxIndex]) {
                    maxIndex = begin;
                }
            }
            int temp = arr[end - 1];
            arr[end - 1] = arr[maxIndex];
            arr[maxIndex] = temp;
        }
    }
	public static void methodMin(Integer[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }

重构后:

    @Override
    protected void sort() {
        for (int end = array.length - 1; end > 0; end--) {
            int maxIndex = 0;
            for (int begin = 1; begin <= end; begin++) {
                if (compare(array[begin], array[maxIndex]) > 0) {
                    maxIndex = begin;
                }
            }
            swap(end, maxIndex);
        }
    }

堆排序

在这里插入图片描述

在这里插入图片描述

public class HeapSort<E> extends Sort<E> {

    private int size;

    @Override
    protected void sort() {
        this.size = array.length;
        heapify();
        while (size > 1) {
            swap(0, size - 1);
            size--;
            siftDown(0);
        }
    }

    private void heapify() {
        for (int i = (size >> 1) - 1; i >= 0; i--) {
            siftDown(i);
        }
    }

    private void siftDown(int index) {
        E element = array[index];
        int half = size >> 1;
        while (index < half) {
            int maxIndex;
            E maxChild;
            int leftChildIndex = index + index + 1;
            E leftChild = array[leftChildIndex];
            maxIndex = leftChildIndex;
            maxChild = leftChild;
            int rightChildIndex = leftChildIndex + 1;
            if (rightChildIndex < size) {
                E rightChild = array[rightChildIndex];
                if (compare(leftChild, rightChild) < 0) {
                    maxIndex = rightChildIndex;
                    maxChild = rightChild;
                }
            }
            if (compare(element, maxChild) >= 0) {
                break;
            }
            array[index] = maxChild;
            index = maxIndex;
        }
        array[index] = element;
    }

}

插入排序

插入排序

/* 从1开始扫描每一个元素,将这个元素和前面已经排好序的元素进行比较,插入到合适的位置 */

在这里插入图片描述

    protected void sort() {
        for (int begin = 1; begin < array.length; begin++) {
            int current = begin;
            while (current > 0 && cmp(current, current - 1) < 0) {
                swap(current, current - 1);
                current--;
            }
        }
    }
逆序对

在这里插入图片描述

优化1—挪动元素

在这里插入图片描述

    // 优化:将“交换”更改为“挪动”
    @Override
    protected void sort() {
        for (int begin = 1; begin < array.length; begin++) {
            int current = begin;
            E element = array[current];
            while (current > 0 && cmp(element, array[current - 1]) < 0) {
                array[current] = array[current - 1];
                current--;
            }
            array[current] = element;
        }
    }
二分搜索

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

public class BinarySearch {

    public static final int ELEMENT_NOT_FOUND = -1;

    /* 左闭右开 */

    public static int indexOf(Integer[] array, int value) {
        if (null == array || array.length == 0) return ELEMENT_NOT_FOUND;
        int begin = 0;
        int end = array.length;
        while (begin < end) { // end - begin > 0 => 该区间范围内的元素个数>0
            int mid = (begin + end) >> 1;
            Integer midElement = array[mid];
            if (value < midElement) {
                end = mid;
            } else if (value > midElement) {
                begin = mid + 1;
            } else {
                return mid;
            }
        }
        return ELEMENT_NOT_FOUND;
    }

}

优化2—二分搜索优化

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

    // 优化:使用二分搜索确定插入的位置,减少比较次数
    @Override
    protected void sort() {
        for (int begin = 1; begin < array.length; begin++) {
            int current = begin;
            E element = array[current];

            // 要求获取第一个大于element的位置
            int b = 0;
            int e = current;
            while (b < e) {
                int m = (b + e) >> 1;
                E midElement = array[m];
                if (cmp(element, midElement) < 0) {
                    e = m;
                } else {
                    b = m + 1;
                }
            }

            while (current > b) {
                array[current] = array[current - 1];
                current--;
            }
            array[b] = element;
        }
    }

归并排序

归并排序

在这里插入图片描述

复杂度分析

在这里插入图片描述

divide

在这里插入图片描述

在这里插入图片描述

merge
merge

在这里插入图片描述

merge细节

在这里插入图片描述

在这里插入图片描述

  • ai应该是从begin开始的

在这里插入图片描述

左边先结束
  • 左边先于右边结束的话,就可以提前结束了,因为右边的元素本来就是大的,处于右边,无须额外操作了。

  • 左边结束后,就不用做其他操作了,就可以结束当前merge了。

在这里插入图片描述

右边先结束

右边先于左边结束的话,将左边数组中剩余的元素一个一个的全部挪到右边数组即可。

在这里插入图片描述

merge实现

在这里插入图片描述

// 牢记左闭右开
public class MergeSort<T extends Comparable<T>> extends Sort<T> {

    private T[] leftArray;

    @Override
    protected void sort() {
        leftArray = (T[]) new Comparable[array.length >> 1];
        sort(0, array.length);
    }

    private void sort(int begin, int end) {
        if (end - begin < 2) return; // 如果只有一个元素就不用排序了
        int middle = (begin + end) >> 1;
        sort(begin, middle);
        sort(middle, end);
        merge(begin, middle, end);
    }

    private void merge(int begin, int middle, int end) {
        int li = 0, le = middle - begin;
        int ri = middle, re = end;
        int ai = begin;
//        for (int i = 0; i < le; i++) {
//            leftArray[i] = array[begin + i];
//        }
        System.arraycopy(array, begin, leftArray, 0, le);
        while (li < le) { // 左边结束后,就不用做其他操作了
            if (ri < re && cmp(array[ri], leftArray[li]) < 0) {
                array[ai++] = array[ri++];
            } else {
                array[ai++] = leftArray[li++];
            }
        }
    }

}

merge其他画法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

快速排序

简介

nlog(n)级别的排序算法中,Quick Sort是最快的。

在这里插入图片描述

执行流程

在这里插入图片描述

在这里插入图片描述

    /**
     * 对[begin, end)范围内的元素进行快速排序
     *
     * @param begin
     * @param end
     */
    private void quickSort(int begin, int end) {
        if (end - begin < 2) return;
        int pivotIndex = pivotIndex(begin, end);// 构造轴点并返回轴点位置
        quickSort(begin, pivotIndex); // 对左子序列进行快排
        quickSort(pivotIndex + 1, end); // 对右子序列进行快排
    }
轴点构造

轴点构造时同样是左闭右开,不过在构造之前,由于先要从右往左扫描,所以首先需要end--一次。

在这里插入图片描述

  • 从右往左扫描时,如果被扫描元素比轴点元素大,只需end–

  • 从右往左扫描时,如果被扫描元素小于或等于轴点元素,array[begin] = array[end]; begin++; 然后更改扫描方向为从左往右

  • 从左往右扫描时,如果被扫描元素比轴点元素小,只需begin++

  • 从左往右扫描时,如果被扫描元素大于或等于轴点元素,array[end] = array[begin]; end–; 然后更改扫描方向为从右往左

  • begin == end时,结束

    // 构造轴点并返回轴点位置
    private int pivotIndex(int begin, int end) {
        E pivot = array[begin]; // 备份begin位置的元素
        end--; // 由于首先是从右往左扫描,所以要将  end--  一次
        while (begin < end) {
            while (begin < end) {
                // 从右往左扫描(注意观察小于号的箭头方向)
                if (cmp(pivot, array[end]) < 0) { // 如果end位置的元素大于pivot元素
                    end--;
                } else {
                    array[begin++] = array[end];
                    break;
                }
            }
            while (begin < end) {
                // 从左往右扫描(注意观察大于号的箭头方向)
                if (cmp(pivot, array[begin]) > 0) { // 如果begin位置的元素小于pivot元素
                    begin++;
                } else {
                    array[end--] = array[begin];
                    break;
                }
            }
        }
        array[begin] = pivot; // 将备份的元素放到pivot轴点处
        return begin; // 返回begin或end都可以,此时begin == end
        // return end;
    }
与轴点相等的元素

与轴点相等的元素应该移动其位置到轴点元素的另一边。

在这里插入图片描述

在这里插入图片描述

时间复杂度

在这里插入图片描述

实现

在这里插入图片描述

public class QuickSort<E extends Comparable<E>> extends Sort<E> {

    @Override
    protected void sort() {
        quickSort(0, array.length);
    }

    /**
     * 对[begin, end)范围内的元素进行快速排序
     *
     * @param begin
     * @param end
     */
    private void quickSort(int begin, int end) {
        if (end - begin < 2) return;
        int pivotIndex = pivotIndex(begin, end);// 构造轴点并返回轴点位置
        quickSort(begin, pivotIndex); // 对左子序列进行快排
        quickSort(pivotIndex + 1, end); // 对右子序列进行快排
    }

    // 构造轴点并返回轴点位置
    private int pivotIndex(int begin, int end) {
        // Math.random() -> [0, 1) // (int)Math.random()永远为0
        // Math.random() * (end - begin) -> [0, end - begin)
        // begin + Math.random() * (end - begin) -> begin + [0, end - begin) -> [begin, end)
        // 随机选取轴点元素
        swap(begin, begin + (int) (Math.random() * (end - begin)));

        E pivot = array[begin]; // 备份begin位置的元素
        end--; // 由于首先是从右往左扫描,所以要将  end--  一次
        while (begin < end) {
            while (begin < end) {
                // 从右往左扫描
                if (cmp(pivot, array[end]) < 0) { // 如果end位置的元素大于pivot元素
                    end--;
                } else {
                    array[begin++] = array[end];
                    break;
                }
            }
            while (begin < end) {
                // 从左往右扫描
                if (cmp(pivot, array[begin]) > 0) { // 如果begin位置的元素小于pivot元素
                    begin++;
                } else {
                    array[end--] = array[begin];
                    break;
                }
            }
        }
        array[begin] = pivot; // 将备份的元素放到pivot轴点处
        return begin; // 返回begin或end都可以,此时begin == end
        // return end;
    }

}

希尔排序

希尔排序

在这里插入图片描述

步长序列

在这里插入图片描述

在这里插入图片描述

举例1

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

举例2

在这里插入图片描述

实现

在这里插入图片描述

public class ShellSort<E extends Comparable<E>> extends Sort<E> {

    @Override
    protected void sort() {
//        希尔排序可自定义步长序列
//        List<Integer> stepSequence = stepSequence();
        List<Integer> stepSequence = sedgewickStepSequence();
        for (Integer step : stepSequence) {
            sort(step);
        }
    }

    // 分为 step 列进行排序
    private void sort(Integer step) {
        for (int col = 0; col < step; col++) {
            // col + row * step;
            // col, col + step, col + 2 * step,    col + 3 * step...
            // col, col + step, col + step + step, col + step + step + step...
//            for (int begin = col + step; begin < array.length; begin += step) {
//                int current = begin;
//                while (current > col && cmp(current, current - step) < 0) {
//                    swap(current, current - step);
//                    current -= step;
//                }
//            }
            for (int begin = col + step; begin < array.length; begin += step) {
                int current = begin;
                E element = array[current];
                while (current > col && cmp(element, array[current - step]) < 0) {
                    array[current] = array[current - step];
                    current -= step;
                }
                array[current] = element;
            }
        }
    }

    private List<Integer> stepSequence() {
        List<Integer> stepSequence = new ArrayList<>();
        int step = array.length;
        while ((step >>= 1) > 0) {
            stepSequence.add(step);
        }
        return stepSequence;
    }

    private List<Integer> sedgewickStepSequence() {
        List<Integer> stepSequence = new ArrayList<>();
        int k = 0, step;
        while (true) {
            if ((k & 1) == 0) {
                int pow = (int) Math.pow(2, k >> 1);
                step = 1 + 9 * (pow * pow - pow);
            } else {
                int pow1 = (int) Math.pow(2, (k - 1) >> 1);
                int pow2 = (int) Math.pow(2, (k + 1) >> 1);
                step = 1 + 8 * pow1 * pow2 - 6 * pow2;
            }
            if (step >= array.length) break;
            stepSequence.add(0, step);
            k++;
        }
        return stepSequence;
    }

}

计数排序

计数排序

适合对一定范围内的整数进行排序

在这里插入图片描述

最简单的实现

在这里插入图片描述

public class CountingSort extends Sort<Integer> {
    @Override
    protected void sort() {
        // 找出最大值
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        // 构建一个计数数组
        int[] counts = new int[max + 1];
        for (int i = 0; i < array.length; i++) {
            counts[array[i]]++;
        }
        // 排序
        int index = 0;
        for (int i = 0; i < counts.length; i++) {
            while (counts[i]-- > 0) {
                array[index++] = i;
            }
        }
    }
}
改进思路—原理

在这里插入图片描述

在这里插入图片描述

改进思路—过程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

改进—实现

在这里插入图片描述

    protected void sort() {
        // 找出最大最小值
        int max = array[0];
        int min = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] < min) {
                min = array[i];
            }
            if (array[i] > max) {
                max = array[i];
            }
        }
        // 开辟新的counts计数数组
        int[] counts = new int[max - min + 1];
        for (int i = 0; i < array.length; i++) {
            counts[array[i] - min]++;
        }
        for (int i = 1; i < counts.length; i++) {
            counts[i] += counts[i - 1];
        }
        // 创建一个临时数组,用于存放排序元素
        int[] tempArray = new int[array.length];
        // 排序 从右往左可以保证稳定性
        for (int i = array.length - 1; i >= 0; i--) {
//            counts[array[i] - min]--;
//            tempArray[counts[array[i] - min]] = array[i];
            tempArray[--counts[array[i] - min]] = array[i];
        }
        for (int i = 0; i < array.length; i++) {
            array[i] = tempArray[i];
        }
    }
对自定义对象进行排序

在这里插入图片描述

在这里插入图片描述

基数排序

基数排序

在这里插入图片描述

实现

在这里插入图片描述

在这里插入图片描述

public class RadixSort extends Sort<Integer> {
    @Override
    protected void sort() {
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        for (int divider = 1; divider <= max; divider *= 10) {
        	// 依次对个位、十位、百位...排序
            countingSort(divider);
        }
    }

    private void countingSort(int divider) {
        // 个位数、十位数等,范围是0-9
        int[] counts = new int[10];
        for (int i = 0; i < array.length; i++) {
/*
        int n = 123;
        int g = n / 1 % 10;   // 个位数
        int s = n / 10 % 10;  // 十位数
        int b = n / 100 % 10; // 百位数

        int g = array[i] / 1 % 10;   // 个位数
        int s = array[i] / 10 % 10;  // 十位数
        int b = array[i] / 100 % 10; // 百位数
*/
            counts[array[i] / divider % 10]++;
        }
        for (int i = 1; i < counts.length; i++) {
            counts[i] += counts[i - 1];
        }
        int[] tempArray = new int[array.length];
        // 计数排序:从右往左可以保证稳定性
        for (int i = array.length - 1; i >= 0; i--) {
            tempArray[--counts[array[i] / divider % 10]] = array[i];
        }
        for (int i = 0; i < array.length; i++) {
            array[i] = tempArray[i];
        }
    }
}

抽取数组出来重新利用:

public class RadixSort extends Sort<Integer> {
    @Override
    protected void sort() {
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        int[] counts = new int[10];
        int[] tempArray = new int[array.length];
        for (int divider = 1; divider <= max; divider *= 10) {
            countingSort(divider, counts, tempArray);
        }
    }

    private void countingSort(int divider, int[] counts, int[] tempArray) {
        for (int i = 1; i < counts.length; i++) { // 重置counts计数数组
            counts[i] = 0;
        }
        for (int i = 0; i < array.length; i++) {
            counts[array[i] / divider % 10]++;
        }
        for (int i = 1; i < counts.length; i++) {
            counts[i] += counts[i - 1];
        }
        for (int i = array.length - 1; i >= 0; i--) {
            tempArray[--counts[array[i] / divider % 10]] = array[i];
        }
        for (int i = 0; i < array.length; i++) {
            array[i] = tempArray[i];
        }
    }
}
另一种思路

在这里插入图片描述

另一种思路—实现

在这里插入图片描述

桶排序

在这里插入图片描述

在这里插入图片描述

休眠排序

休眠排序——史上最强排序,复杂度竟为O(n)!

在这里插入图片描述

C语言实现十大排序算法(除过桶排序)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <malloc.h>

#define MAX 10

void swap(int* array, int i1, int i2);
int* generateArray(int size);
int* copyArray(int* arr, int size);
void printArray(char* name, int* array, int size);
void isArcSort(char* name, int* array, int size);
void afterSort(char* name, int* array, int size);

typedef struct node {
	int step;
	struct node* next;
} Node;

void _radixSort(int* counts, int* tempArray, int* array, int size, int divider) {
	for (int i = 0; i < 10; i++) {
		counts[i] = 0;
	}
	for (int i = 0; i < size; i++) {
		counts[array[i] / divider % 10]++;
	}
	for (int i = 1; i < 10; i++) {
		counts[i] += counts[i - 1];
	}
	for (int i = size - 1; i >= 0; i--) {
		tempArray[--counts[array[i] / divider % 10]] = array[i];
	}
	for (int i = 0; i < size; i++) {
		array[i] = tempArray[i];
	}
}

void radixSort(int* arr, int size) {
	int* array = copyArray(arr, size);
	int max = array[0];
	for (int begin = 1; begin < size; begin++) {
		if (array[begin] > max) {
			max = array[begin];
		}
	}
	int* counts = calloc(sizeof(int), 10);
	int* tempArray = malloc(sizeof(int) * size);
	for (int divider = 1; divider <= max; divider *= 10) {
		_radixSort(counts, tempArray, array, size, divider);
	}
	afterSort("radixSort", array, size);
}

void countingSort(int* arr, int size) {
	int* array = copyArray(arr, size);
	int max = array[0];
	int min = array[0];
	for (int begin = 1; begin < size; begin++) {
		if (array[begin] > max) {
			max = array[begin];
		}
		if (array[begin] < min) {
			min = array[begin];
		}
	}
	int countsSize = max - min + 1;
	int* counts = calloc(sizeof(int), countsSize);
	for (int i = 0; i < size; i++) {
		counts[array[i] - min]++;
	}
	for (int i = 1; i < countsSize; i++) {
		counts[i] += counts[i - 1];
	}
	int* tempArray = malloc(sizeof(int)*size);
	for (int i = size - 1; i >= 0; i--) {
		tempArray[--counts[array[i] - min]] = array[i];
	}
	for (int i = 0; i < size; i++) {
		array[i] = tempArray[i];
	}
	afterSort("countingSort", array, size);
}

Node* generateStepSequence(int arraySize) {
	int step = arraySize;
	Node* node = malloc(sizeof(Node));
	Node* temp = node;
	Node* prevNode = NULL;
	while ((step >>= 1) > 0) {
		prevNode = node;
		node->step = step;
		node->next = malloc(sizeof(Node));
		node = node->next;
	}
	free(prevNode->next);
	prevNode->next = NULL;
	return temp;
}

void _shellSort(int* array, int size, int step) {
	for (int col = 0; col < step; col++) {
		for (int begin = col + step; begin < size; begin += step) {
			int currentElement = array[begin];
			int currentIndex = begin;
			while (currentIndex > col && currentElement < array[currentIndex - step]) {
				array[currentIndex] = array[currentIndex - step];
				currentIndex -= step;
			}
			array[currentIndex] = currentElement;
		}
	}
}

void shellSort(int* arr, int size) {
	int* array = copyArray(arr, size);
	Node* stepSequence = generateStepSequence(size);
	Node* temp = stepSequence;
	while (stepSequence != NULL) {
		_shellSort(array, size, stepSequence->step);
		stepSequence = stepSequence->next;
	}
	stepSequence = temp; // 释放内存
	while (stepSequence != NULL) {
		temp = stepSequence;
		stepSequence = stepSequence->next;
		free(temp);
	}
	afterSort("shellSort", array, size);
}

int createPivotIndex(int* array, int begin, int end) {
	int pivotElement = array[begin];
	end--;
	while (begin < end) {
		while (begin < end) {
			if (array[end] > pivotElement) {
				end--;
			}
			else {
				array[begin++] = array[end];
				break;
			}
		}
		while (begin < end) {
			if (array[begin] < pivotElement) {
				begin++;
			}
			else {
				array[end--] = array[begin];
				break;
			}
		}
	}
	array[begin] = pivotElement;
	return begin;
}

void _quickSort(int* array, int begin, int end) {
	if (end - begin < 2) return;
	int pivotIndex = createPivotIndex(array, begin, end);
	_quickSort(array, begin, pivotIndex);
	_quickSort(array, pivotIndex + 1, end);
}

void quickSort(int* arr, int size) {
	int* array = copyArray(arr, size);
	_quickSort(array, 0, size);
	afterSort("quickSort", array, size);
}

void merge(int* leftArray, int* array, int begin, int middle, int end) {
	int li = 0, le = middle - begin;
	int ri = middle, re = end;
	int ai = begin;
	for (int i = 0; i < le; i++) {
		leftArray[i] = array[begin + i];
	}
	while (li < le) {
		if (ri < re && array[ri] < leftArray[li]) {
			array[ai++] = array[ri++];
		} else {
			array[ai++] = leftArray[li++];
		}
	}
}

void _mergeSort(int* leftArray, int* array, int begin, int end) {
	if (end - begin < 2) return;
	int middle = (begin + end) >> 1;
	_mergeSort(leftArray, array, begin, middle);
	_mergeSort(leftArray, array, middle, end);
	merge(leftArray, array, begin, middle, end);
}

void mergeSort(int* arr, int size) {
	int* array = copyArray(arr, size);
	int* leftArray =  malloc(sizeof(int) * (size >> 1));
	_mergeSort(leftArray, array, 0, size);
	afterSort("mergeSort", array, size);
	free(leftArray);
}

void insertionSort(int* arr, int size) {
	int* array = copyArray(arr, size);
	for (int begin = 1; begin < size; begin++) {
		int currentIndex = begin;
		int currentElement = array[currentIndex];
		int b = 0;
		int e = begin;
		while (b < e) {
			int m = (b + e) >> 1;
			if (currentElement < array[m]) {
				e = m;
			} else {
				b = m + 1;
			}
		}
		while (currentIndex > b) {
			array[currentIndex] = array[currentIndex - 1];
			currentIndex--;
		}
		array[b] = currentElement;
	}
	afterSort("insertionSort", array, size);
}

void siftDown(int* array, int heapSize, int index) {
	int half = heapSize >> 1;
	int currentElement = array[index];
	while (index < half) {
		int leftChildIndex = (index << 1) + 1;
		int leftChildElement = array[leftChildIndex];
		int rightChildIndex = leftChildIndex + 1;
		if (rightChildIndex < heapSize) {
			int rightChildElement = array[rightChildIndex];
			if (rightChildElement > leftChildElement) {
				leftChildElement = rightChildElement;
				leftChildIndex = rightChildIndex;
			}
		}
		if (currentElement >= leftChildElement) break;
		array[index] = leftChildElement;
		index = leftChildIndex;
	}
	array[index] = currentElement;
}

void heapSort(int* arr, int size) {
	int* array = copyArray(arr, size);
	int heapSize = size;
	for (int i = (size >> 1) - 1; i >= 0; i--) {
		siftDown(array, heapSize, i);
	}
	while (heapSize > 1) {
		swap(array, 0, --heapSize);
		siftDown(array, heapSize, 0);
	}
	afterSort("heapSort", array, size);
}

void selectionSort(int* arr, int size) {
	int* array = copyArray(arr, size);
	for (int end = size - 1; end > 0; end--) {
		int max =0;
		for (int begin = 1; begin <= end; begin++) {
			if (array[begin] > array[max]) {
				max = begin;
			}
		}
		swap(array, max, end);
	}
	afterSort("selectionSort", array, size);
}

void bubbleSort(int* arr, int size) {
	int* array = copyArray(arr, size);
	for (int end = size - 1; end > 0; end--) {
		int sortedIndex = 1;
		for (int begin = 1; begin <= end; begin++) {
			if (array[begin - 1] > array[begin]) {
				swap(array,begin - 1, begin);
				sortedIndex = begin;
			}
		}
		end = sortedIndex;
	}
	afterSort("bubbleSort", array, size);
}

int main() {
	int * array = generateArray(MAX);
	printArray("original", array, MAX);

	bubbleSort(array, MAX);
	selectionSort(array, MAX);
	heapSort(array, MAX);
	insertionSort(array, MAX);
	mergeSort(array, MAX);
	quickSort(array, MAX);
	shellSort(array, MAX);
	countingSort(array, MAX);
	radixSort(array, MAX);

	free(array);
	return 0;
}

void afterSort(char* name, int* array, int size) {
	printArray(name, array, size);
	isArcSort(name, array, size);
	free(array);
}

void swap(int* array, int i1, int i2) {
	int temp = array[i1];
	array[i1] = array[i2];
	array[i2] = temp;
}

void isArcSort(char* name, int* array, int size) {
	int isArc = 1;
	for (int i = 1; i < size; i++) {
		if (array[i - 1] > array[i]) {
			isArc = 0;
		}
	}
	if (!isArc) printf("%s is not arc!\n", name);
}

int* copyArray(int* arr, int size) {
	int* array = malloc(sizeof(int) * size);
	for (int i = 0; i < size; i++) {
		array[i] = arr[i];
	}
	return array;
}

int* generateArray(int size) {
	int* array = malloc(sizeof(int) * size);
	srand((unsigned)time(NULL));
	for (int i = 0; i < size; i++) {
		array[i] = rand() % (size << 2);
	}
	return array;
}

void printArray(char* name, int* array, int size) {
	//if (1) return;
	printf("%13s : ", name);
	for (int i = 0; i < size; i++) {
		printf("%d ", array[i]);
	}
	printf("\n");
}

注意

  • 左闭右开

  • 类似于最大堆和最小堆那样:最大堆其实就是最小堆,最小堆其实也是最大堆。(只不过比较时对元素大小的看法不同)

  • 排序时,升序排序或者降序排序其实可以理解为是同一种排序(从小到大排或者从大到小排都行,以从小到大升序为例),当实现了一个从小到大的升序排序算法时,也就相当于实现了一个从大到小的降序排序算法,只不过,在比较元素大小时(compare),看你如何认为什么是大的元素如何认为什么是小的元素。

  • 如果认为值比较大的元素比较大,那么就是正常的升序排序。

  • 而如果认为值比较小的元素比较大,那么就是降序排序了。


  • 求某个数的个位数、百位数、十位数…
        int i = 423;
        int g = i / 1 % 10; // 个位数
        int s = i / 10 % 10; // 十位数
        int b = i / 100 % 10; // 百位数
//        int q = i / 1000 % 10; // 千位数
//        ......

参考

小码哥李明杰老师课程: 恋上数据结构与算法 第二季.


本文完,感谢您的关注支持!


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值