三、排序算法

一、排序算法的介绍

在这里插入图片描述

二、算法的时间复杂度

2.1 基本介绍

在这里插入图片描述

2.2 时间频度

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.3 时间复杂度的表示

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.4 算法的平均时间复杂度和最坏时间复杂度

在这里插入图片描述

三、算法的空间复杂度

在这里插入图片描述

四、排序算法

4.1 交换排序

4.1.1 冒泡排序

在这里插入图片描述

在这里插入图片描述

package com.gyh.sort;

import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class BubbleSort {
    public static void main(String[] args) {
        int[] nums = {2, 84, 17, 291, 92, 17, 817, 17};
        sort(nums, true);
        Arrays.stream(nums).forEach(System.out::println);
    }

    /**
     * 排序方法
     *
     * @param nums      需要排序的数组
     * @param ascending 是否升序
     */
    private static void sort(int[] nums, boolean ascending) {
        int temp;
        boolean flag; // 标志位判断是否有一次遍历没有交换数据
        // 走几趟
        for (int i = 0; i < nums.length - 1; i++) {
            // 每一趟需要的遍历
            flag = true;
            for (int j = 0; j < nums.length - 1 - i; j++) {
                if (ascending) {
                    if (nums[j] > nums[j + 1]) { // 不添加等号,使排序稳定
                        temp = nums[j];
                        nums[j] = nums[j + 1];
                        nums[j + 1] = temp;
                        if (flag) flag = false;
                    }
                } else {
                    if (nums[j] < nums[j + 1]) { // 不添加等号,使排序稳定
                        temp = nums[j];
                        nums[j] = nums[j + 1];
                        nums[j + 1] = temp;
                        if (flag) flag = false;
                    }
                }
            }
            if (flag) {
                return;
            }
        }
    }

}

4.1.2 快速排序

在这里插入图片描述

在这里插入图片描述

//  以首元素作为中轴值的快排
package com.gyh.sort;

import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 * 以首元素作为中轴值的快排
 */
public class QuickSort2 implements Sort {
    public static void main(String[] args) {
        int[] nums = {2, 1, 17, 291, 92, 17, 817, 17};
        new QuickSort2().sort(nums, false);
        Arrays.stream(nums).forEach(System.out::println);
    }

    @Override
    public void sort(int[] nums, boolean ascending) {
        sort(nums, 0, nums.length - 1, ascending);
    }

    private void sort(int[] nums, int low, int high, boolean ascending) {
        // 设置第一个元素为中轴值(此时low位置被挖空)
        int pivot = nums[low];
        int l = low;
        int h = high;
        while (l < h) {
            //
            while (l < h && (ascending ? nums[h] >= pivot : nums[h] <= pivot)) {
                h--;
            }
            nums[l] = nums[h];

            while (l < h && (ascending ? nums[l] <= pivot : nums[l] >= pivot)) l++;
            nums[h] = nums[l];
        }
        // 此时 l=h 对应位置即为中轴最终位置
        nums[l] = pivot;
        // 分别对左右进行递归
        if (l - 1 > low) {
            sort(nums, low, l - 1, ascending);
        }
        // 此时 l = h
        if (l + 1 < high) {
            sort(nums, l + 1, high, ascending);
        }
    }
}

// 以中间元素作为中轴值的快速排序
package com.gyh.sort;

import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class QuickSort implements Sort {
    public static void main(String[] args) {
        int[] nums = new int[11];
        for (int i = 0; i < nums.length; i++) {
            nums[i] = i + 1;
        }
        nums[1] = 9;
        new QuickSort().sort(nums, true);
        Arrays.stream(nums).forEach(System.out::println);
    }

    @Override
    public void sort(int[] nums, boolean ascending) {
        sort(nums, 0, nums.length - 1, ascending);
    }

    private void sort(int[] nums, int left, int right, boolean ascending) {
        int l = left;
        int r = right;
        int temp;
        // pivot 中轴值
        int pivot = nums[(left + right) / 2];
        while (l < r) {
            // 在pivot的左边一直找,找到大于等于pivot值,才退出
            // 存在情况是没有大于等于的元素
            while (ascending ? nums[l] < pivot : nums[l] > pivot) {
                l++;
            }

            // 在pivot的右边一直找,找到小于等于pivot值,才退出
            // 存在情况是没有大于等于的元素
            while (ascending ? nums[r] > pivot : nums[r] < pivot) {
                r--;
            }

            // 如果 l >= r 说明 pivot 的左右两边的值,已经按照左边全部小于等于 pivot
            // 右边全部大于于等于 pivot 分布
            if (l >= r) {
                break;
            }

            // 交换搜索到的 l 与 r 的值
            temp = nums[l];
            nums[l] = nums[r];
            nums[r] = temp;


            if (nums[l] == pivot) {
                r--;
            }
            if (nums[r] == pivot) {
                l++;
            }
        }
        if (l == r) {
            l += 1;
            r -= 1;
        }
        if (left < r) {
            sort(nums, left, r, ascending);// 左边
        }
        if (right > l) {
            sort(nums, l, right, ascending);// 右边
        }

    }
}

4.2 选择排序

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.2.1 简单选择排序

在这里插入图片描述

package com.gyh.sort;

import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 * 简单快速排序
 */
public class SimpleSelectSort implements Sort {
    public static void main(String[] args) {
        int[] nums = {101, 34, 119, 1};
        new SimpleSelectSort().sort(nums, false);
        Arrays.stream(nums).forEach(System.out::println);
    }


    @Override
    public void sort(int[] nums, boolean ascending) {
        int index;
        int temp;
        // 走几轮
        for (int i = 0; i < nums.length - 1; i++) {
            // 升序排法
            index = i;
            for (int j = i + 1; j < nums.length; j++) {
                if (ascending) {
                    if (nums[j] < nums[index]) {
                        index = j;
                    }
                } else {
                    if (nums[j] > nums[index]) {
                        index = j;
                    }
                }
            }
            if (index != i) {// 若就是本位则无需交换
                temp = nums[index];
                nums[index] = nums[i];
                nums[i] = temp;
            }
        }
    }
}

4.2.2 堆排序

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.gyh.sort;

import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class HeapSort implements Sort {
    public static void main(String[] args) {
        int[] nums = {2, 1, 17, 291, 92, 17, 817, 17};
        new HeapSort().sort(nums, true);
        Arrays.stream(nums).forEach(System.out::println);
    }

    @Override
    public void sort(int[] nums, boolean ascending) {
        if (nums == null || nums.length <= 1) {
            return;
        }
        // 初始化堆
        createHeap(nums, ascending);

        int temp;
        for (int i = nums.length - 1; i > 0; i--) {
            // 将堆顶元素与最后位置元素交换
            temp = nums[i];
            nums[i] = nums[0];
            nums[0] = temp;
            // 从第一层堆顶再次调整堆
            heapAdjust(nums, 0, i - 1, ascending);
        }
    }

    /**
     * 作为完全二叉树的排序算法,最后一个非叶子结点的数组下标为 arr.length/2 - 1
     * 从该位置依次向前进行向上的筛选
     *
     * @param arr       待排序数组
     * @param ascending 是否升序
     */
    private void createHeap(int[] arr, boolean ascending) {
        if (arr == null || arr.length <= 0) {
            return;
        }
        int n = arr.length / 2 - 1;
        // 从最后一个非叶子结点依次向堆顶进行筛选
        for (int i = n; i >= 0; i--) {
            heapAdjust(arr, i, arr.length - 1, ascending);
        }
    }


    /**
     * 使用筛选法调整堆(以堆为前提,至上而下的调整)
     *
     * @param arr       待调整数组
     * @param org       待筛选的堆顶
     * @param dis       数组的最后的元素下标(对应最后一个堆的位置)
     * @param ascending 是否升序
     */
    private void heapAdjust(int[] arr, int org, int dis, boolean ascending) {
        // 假设[org+1,dis]均为堆,现将[org,dis]调整为堆

        // 依次向下进行筛选(仅筛选与根节点交换的子树是否是堆)
        // 对于初始化堆:最先对其最后一个非终端结点的左子树根节点与右子树根节点进行比较
        int r = arr[org]; // 先保存根元素
        for (int i = 2 * org + 1; i <= dis; i = i * 2 + 1) {
            // i < dis 保证了初始化堆中的最后一个非终端结点存在左结点与右结点
            // 若 i == dis 则仅存在左结点
            // 筛选出子节点中最大(小)元素对应的下标
            if (i < dis && (ascending ? arr[i] < arr[i + 1] : arr[i] > arr[i + 1])) i++;

            // 已满足堆,则退出(r应该插入当前结点的双亲结点)
            if (ascending ? r >= arr[i] : r <= arr[i]) break;

            arr[org] = arr[i]; // 最值赋给堆顶
            org = i; // 重置新的堆顶位置
        }

        // 将最后的堆的堆顶设置为初始待调整的值
        arr[org] = r;

    }
}

4.3 插入排序

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.3.1 直接插入排序

在这里插入图片描述

在这里插入图片描述

package com.gyh.sort;

import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class DirectInsetSort implements Sort {
    public static void main(String[] args) {
        int[] nums = {2, 1, 17, 291, 92, 17, 817, 17};
        new DirectInsetSort().sort(nums, false);
        Arrays.stream(nums).forEach(System.out::println);
    }

    @Override
    public void sort(int[] nums, boolean ascending) {
        int insetIndex;
        int insertValue;

        // 前 i 个元素组成有序表,后 nums.length - i 个元素组成无序表
        for (int i = 1; i < nums.length; i++) {
            insetIndex = i - 1; // 保存无序表首元素的前一个位置
            insertValue = nums[i];
            // 条件一:限定数据边界
            // 条件二:设置升(降)序的判断
            while (insetIndex >= 0 && (ascending ? nums[insetIndex] > insertValue : nums[insetIndex] < insertValue)) {
                nums[insetIndex + 1] = nums[insetIndex]; // 数组元素移动位置(前一元素覆盖后一元素)
                insetIndex--;
            }
            // 判断是否需要赋值
            if (insetIndex + 1 != i) {
                nums[insetIndex + 1] = insertValue;
            }

        }
    }
}

4.3.2 折半插入排序(书上补充P238)

package com.gyh.sort;

import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class BinaryInsertSort implements Sort {
    public static void main(String[] args) {
        int[] nums = {2, 1, 17, 291, 92, 17, 817, 17};
        new BinaryInsertSort().sort(nums, false);
        Arrays.stream(nums).forEach(System.out::println);
    }

    @Override
    public void sort(int[] nums, boolean ascending) {
        int low, high, mid;
        int temp;
        // 从第二个位置开始
        for (int i = 1; i < nums.length; i++) {
            low = 0;
            high = i - 1;
            while (low <= high) {
                mid = (low + high) / 2; // 中间元素的位置
                if (ascending ? nums[mid] > nums[i] : nums[mid] < nums[i]) { // 不加等号保证稳定
                    high = mid - 1;
                } else {
                    low = mid + 1;
                }
            }
            // 待插入位置位于high之后一个位置
            // 特殊的如果待插入元素比有序表的尾元素还大(小)则不会进行后移操作
            temp = nums[i];
            for (int j = i - 1; j >= high + 1; j--) {
                nums[j + 1] = nums[j];
            }
            nums[high + 1] = temp;

        }
    }
}

4.3.3 希尔排序

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

// 交换法(慢)
package com.gyh.sort;

import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class ShellSort implements Sort {
    public static void main(String[] args) {
        int[] nums = {2, 1, 17, 291, 92, 17, 817, 17, 3};
        new ShellSort().sort(nums, false);
        /**
         * 希尔排序第1轮 =[92, 17, 817, 291, 3, 1, 17, 17, 2]
         * 希尔排序第2轮 =[817, 291, 92, 17, 17, 17, 3, 1, 2]
         * 希尔排序第3轮 =[817, 291, 92, 17, 17, 17, 3, 2, 1]
         */
        Arrays.stream(nums).forEach(System.out::println);
    }


    @Override
    public void sort(int[] nums, boolean ascending) {
        int temp;
        int count = 0;
        for (int gap = nums.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < nums.length; i++) {
                // 遍历各组中所有的元素(共gap组),步长为 gap
                for (int j = i - gap; j >= 0; j -= gap) {
                    if (ascending ? nums[j] > nums[j + gap] : nums[j] < nums[j + gap]) {
                        temp = nums[j];
                        nums[j] = nums[j + gap];
                        nums[j + gap] = temp;
                    }
                }
            }
            System.out.println("希尔排序第" + (++count) + "轮 =" + Arrays.toString(nums));


        }
    }
}

// 移位法(快)
package com.gyh.sort;

import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class ShellSort2 implements Sort {
    public static void main(String[] args) {
        int[] nums = {2, 1, 17, 291, 92, 17, 817, 17};
        new ShellSort2().sort(nums, false);
        Arrays.stream(nums).forEach(System.out::println);
    }

    @Override
    public void sort(int[] nums, boolean ascending) {
        int count = 0;
        for (int gap = nums.length / 2; gap > 0; gap /= 2) {
            // i是无序序列的第一个元素
            for (int i = gap; i < nums.length; i++) {
                int insetIndex = i - gap; // 同一组的前一个元素
                int insertValue = nums[i];
                while (insetIndex >= 0 && (ascending ? nums[insetIndex] > insertValue : nums[insetIndex] < insertValue)) {
                    nums[insetIndex + gap] = nums[insetIndex];// 同组前一元素覆盖后一元素
                    insetIndex -= gap;
                }
                nums[insetIndex + gap] = insertValue;
            }
            System.out.println("希尔排序第" + (++count) + "轮 =" + Arrays.toString(nums));
        }
    }
}

五、归并排序

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.gyh.sort;

import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class MergingSort implements Sort {

    public static void main(String[] args) {
        int[] nums = {8, 4, 5, 7, 1, 3, 6, 2,9};
        new MergingSort().sort(nums, true);
        Arrays.stream(nums).forEach(System.out::println);
    }

    @Override
    public void sort(int[] nums, boolean ascending) {
        mergeSort(nums, 0, nums.length - 1, new int[nums.length], ascending);
    }

    private void mergeSort(int[] nums, int left, int right, int[] temp, boolean ascending) {
        int mid;
        if (left < right) {
            mid = (left + right) / 2;
            mergeSort(nums, left, mid, temp, ascending); // 归并左边
            mergeSort(nums, mid + 1, right, temp, ascending); // 归并右边
            merge(nums, left, mid, right, temp, ascending); // 合并当前
        }
    }

    private void merge(int[] nums, int left, int mid, int right, int[] temp, boolean ascending) {
        // 左、右边有序表的位置指针初始化
        int l = left;
        int r = mid + 1;
        int cur = 0;
        while (l <= mid && r <= right) {
            if (ascending ? nums[l] <= nums[r] : nums[l] >= nums[r]) { // 等号实现稳定
                temp[cur++] = nums[l++];
            } else {
                temp[cur++] = nums[r++];
            }
        }

        // 把剩余一边的有序序列依次填充至temp
        while (l <= mid) temp[cur++] = nums[l++];
        while (r <= right) temp[cur++] = nums[r++];

        // 将中间结果保存至原数组
        int tempLeft = left;
        cur = 0;
        while (tempLeft <= right) {
            nums[tempLeft++] = temp[cur++];
        }
    }
}

六、基数排序

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package com.gyh.sort;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * @author Gao YongHao
 * @version 1.0
 */
public class RadixSorting implements Sort {
    public static void main(String[] args) {
        int[] nums = {2, 84, 17, 291, 92, 17, 817, 17};
        new RadixSorting().sort(nums, false);
        Arrays.stream(nums).forEach(System.out::println);
    }

    @Override
    public void sort(int[] nums, boolean ascending) {
        // 找到最大值(确定关键字(d)的个数)
        int max = nums[0];
        for (int num : nums) {
            if (num > max) {
                max = num;
            }
        }
        // 计算关键字个数(位数)
        int maxLength = (max + "").length();

        // 使用(链表)队列的基数排序(桶的个数有各关键字的取值范围决定)
        // 本例中 关键字是:位数  各位数上的范围是:0-9
        ArrayList<LinkedQueue<Integer>> bucket = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            bucket.add(new LinkedQueue<>());
        }
        int cur;
        for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
            // 先分配
            for (int num : nums) {
                // 取出指定位上的元素值
                int digitOfElement = num / n % 10;
                bucket.get(digitOfElement).push(num);
            }

            // 再收集
            cur = 0;
            // 升序(正向收集)
            // 降序(反向收集)
            for (int j = 0; j < bucket.size(); j++) {
                LinkedQueue<Integer> integerLinkedQueue = bucket.get(ascending ? j : bucket.size() - j - 1);
                while (integerLinkedQueue.size() > 0) {
                    nums[cur++] = integerLinkedQueue.pop();
                }
            }

        }


    }


}


class LinkedQueue<T> {
    // 设置头结点
    private final Node<T> head;
    // 设置队尾元素指针
    private Node<T> rear;

    private int size = 0;

    public int size() {
        return size;
    }

    public LinkedQueue() {
        // 起始位置头尾指针均指向头结点
        rear = new Node<>(null, null);
        head = rear;
    }

    public boolean isEmpty() {
        return head.next == null;
    }

    public void push(T d) {
        rear.next = new Node<>(d, rear.next);
        rear = rear.next;
        size++;
    }

    public T pop() {
        if (isEmpty()) {
            throw new RuntimeException("没有元素");
        }

        T d = head.next.data;
        // 如果删除的是最后一个元素,则重置rear
        if (rear == head.next) {
            rear = head;
        }

        head.next = head.next.next;
        size--;
        return d;
    }

}

class Node<T> {
    T data;
    Node<T> next;

    public Node(T data, Node<T> next) {
        this.data = data;
        this.next = next;
    }
}

七、排序算法总结

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ModelBulider

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值