IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 排序算法总结 -> 正文阅读

[数据结构与算法]排序算法总结

1. 排序算法

冒泡排序

public static void bubbleSort(int[] arr) {
    boolean swapped = true;
    // 最后一个没有经过排序的元素的下标
    int indexOfLastUnsortedElement = arr.length - 1;
    // 上次发生交换的位置
    int swappedIndex = -1;
    while (swapped) {
        swapped = false;
        for (int i = 0; i < indexOfLastUnsortedElement; i++) {
            if (arr[i] > arr[i + 1]) {
                // 如果左边的数大于右边的数,则交换,保证右边的数字最大
                swap(arr, i, i + 1);
                // 表示发生了交换
                swapped = true;
                // 更新交换的位置
                swappedIndex = i;
            }
        }
        // 最后一个没有经过排序的元素的下标就是最后一次发生交换的位置
        indexOfLastUnsortedElement = swappedIndex;
    }
}
// 交换元素
private static void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}


  1. 把数组排成最小的数
    剑指offer 45
    思路:重新定义数大小的规则 如果 2,10 因为210>102 所以10放在2的前面

  2. 移动零
    link
    将所有0移动到数组末尾 并保持相对顺序 对数组原地操作
    思路:冒泡排序
    思路二:设置非0的个数计数 如果当前值为非0 则将该值移至cnt-1的位置

选择排序

优化:二元选择排序 同时找到最大和最小值

插入排序

class Solution {
    public int[] sortArray(int[] nums) {
        insertSort(nums);
        return nums;
    }

    public static void insertSort(int[] arr) {
        // 从第二个数开始,往前插入数字
        for (int i = 1; i < arr.length; i++) {
            int currentNumber = arr[i];
            int j = i - 1;
            // 寻找插入位置的过程中,不断地将比 currentNumber 大的数字向后挪
            while (j >= 0 && currentNumber < arr[j]) {
                arr[j + 1] = arr[j];
                j--;
            }
            // 两种情况会跳出循环:1. 遇到一个小于或等于 currentNumber 的数字,跳出循环,currentNumber 就坐到它后面。
            // 2. 已经走到数列头部,仍然没有遇到小于或等于 currentNumber 的数字,也会跳出循环,此时 j 等于 -1,currentNumber 就坐到数列头部。
            arr[j + 1] = currentNumber;
        }
    }
}

优化:插入时用二分查找优化

应用:对链表进行插入排序
link
思路:如果当前节点比前一节点大时,则无需交换,否则从首节点前的结点开始比较。
插入时,要先把next赋值,如果先赋值当前节点则找不到next

希尔排序

对插入排序的优化,插入排序每次只能交换相邻元素。
思想:
每次排序的间隔 K=N/2 K=K/2

实现:

    public static void shellSort(int[] arr) {
        // 间隔序列,在希尔排序中我们称之为增量序列
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            // 从 gap 开始,按照顺序将每个元素依次向前插入自己所在的组
            for (int i = gap; i < arr.length; i++) {
                // currentNumber 站起来,开始找位置
                int currentNumber = arr[i];
                // 该组前一个数字的索引
                int preIndex = i - gap;
                while (preIndex >= 0 && currentNumber < arr[preIndex]) {
                    // 向后挪位置
                    arr[preIndex + gap] = arr[preIndex];
                    preIndex -= gap;
                }
                // currentNumber 找到了自己的位置,坐下
                arr[preIndex + gap] = currentNumber;
            }
        }
    }

堆排序

针对于只需要部分排序的场景,例如前K个访问最多的元素

非稳定算法:初始化堆和重建堆的时间复杂度:O(nlogn)
完全二叉树性质:
节点i的左孩子节点:l=2*i+1 右孩子节点:r=l+1
对于有 n个元素的完全二叉树(n≥2),它的最后一个非叶子结点的下标:n/2 - 1

每次调整完堆后要递归到当前结点的下面,被换下来的最大值的下面节点

代码:

public static void heapSort(int[] arr) {
    // 构建初始大顶堆
    buildMaxHeap(arr);
    for (int i = arr.length - 1; i > 0; i--) {
        // 将最大值交换到数组最后
        swap(arr, 0, i);
        // 调整剩余数组,使其满足大顶堆
        maxHeapify(arr, 0, i);
    }
}
// 构建初始大顶堆
private static void buildMaxHeap(int[] arr) {
    // 从最后一个非叶子结点开始调整大顶堆,最后一个非叶子结点的下标就是 arr.length / 2-1
    for (int i = arr.length / 2 - 1; i >= 0; i--) {
        maxHeapify(arr, i, arr.length);
    }
}
// 调整大顶堆,第三个参数表示剩余未排序的数字的数量,也就是剩余堆的大小
private static void maxHeapify(int[] arr, int i, int heapSize) {
    // 左子结点下标
    int l = 2 * i + 1;
    // 右子结点下标
    int r = l + 1;
    // 记录根结点、左子树结点、右子树结点三者中的最大值下标
    int largest = i;
    // 与左子树结点比较
    if (l < heapSize && arr[l] > arr[largest]) {
        largest = l;
    }
    // 与右子树结点比较
    if (r < heapSize && arr[r] > arr[largest]) {
        largest = r;
    }
    if (largest != i) {
        // 将最大值交换为根结点
        swap(arr, i, largest);
        // 再次调整交换数字后的大顶堆
        maxHeapify(arr, largest, heapSize);
    }
}
private static void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

归并排序

快速排序

经典快排模板

    public void partion(int[] nums,int k,int l,int r){
        if(l>=r)return;
        int cur=nums[l];
        int i=l;
        int j=r;
        while(i<j){
            while(i<j&&nums[j]>=cur){
            j--;
          }
           while(i<j&&nums[i]<=cur){
            i++;
          }
          swap(nums,i,j);
        }
        swap(nums,i,l);
        if(i==k)return;
        if(i>k){
            partion(nums,k,l,i-1);
        }else{
            partion(nums,k,i+1,r);
        }
    }

数组中的第K个最大元素
思路1:减治(快速排序)
实现步骤:随机选择一个数,将大于这个数的都放该数的右边,小于该数的都放左边
思路2:优先队列 小堆顶

class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(k);
        for (int i = 0; i < nums.length; i++) {
            priorityQueue.add(nums[i]);
            if (priorityQueue.size() > k) {
                priorityQueue.poll();
            }
        }
        return priorityQueue.peek();
    }
}

思路3:堆排序

class Solution {
    public int findKthLargest(int[] nums, int k) {
        buildMaxHeap(nums);
        // 调整 k-1 次
        for (int i = nums.length - 1; i > nums.length - k; i--) {
            swap(nums, 0, i);
            maxHeapify(nums, 0, i);
        }
        // 此时,堆顶的元素就是第 k 大的数
        return nums[0];
    }

    // 构建初始大顶堆
    public static void buildMaxHeap(int[] arr) {
        // 从最后一个非叶子结点开始调整大顶堆,最后一个非叶子结点的下标就是 arr.length / 2-1
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            maxHeapify(arr, i, arr.length);
        }
    }

    // 调整大顶堆,第三个参数表示剩余未排序的数字的数量,也就是剩余堆的大小
    private static void maxHeapify(int[] arr, int i, int heapSize) {
        // 左子结点下标
        int l = 2 * i + 1;
        // 右子结点下标
        int r = l + 1;
        // 记录根结点、左子树结点、右子树结点三者中的最大值下标
        int largest = i;
        // 与左子树结点比较
        if (l < heapSize && arr[l] > arr[largest]) {
            largest = l;
        }
        // 与右子树结点比较
        if (r < heapSize && arr[r] > arr[largest]) {
            largest = r;
        }
        if (largest != i) {
            // 将最大值交换为根结点
            swap(arr, i, largest);
            // 再次调整交换数字后的大顶堆
            maxHeapify(arr, largest, heapSize);
        }
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

基数排序

基数排序可以分为以下三个步骤:

  1. 找出数组中最大的数字的位数 maxDigitLength

  1. 获取数组中每个数字的基数
  2. 遍历 maxDigitLength轮数组,每轮按照基数对其进行排序
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 11:07:37  更:2022-08-06 11:08:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:42:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码