当前位置: 首页 > news >正文

数据结构与算法之排序算法-选择排序

排序算法是数据结构与算法中最基本的算法之一,其作用就是将一些可以比较大小的数据进行有规律的排序,而想要实现这种排序就拥有很多种方法~

那么我将通过几篇文章,将排序算法中各种算法细化的,详尽的为大家呈现出来:

📚 非线性时间比较类

📕 插入类排序:数据结构与算法之排序算法-插入排序-CSDN博客

📖 直接插入排序

📖 希尔排序

📕 交换类排序:数据结构与算法之排序算法-快速排序(分治)-CSDN博客

📖 冒泡排序

📖 冒泡排序-优化

📖 快速排序(Hoare,挖坑法,前后指针法)

📖 快速排序-优化

📕 选择类排序:[本篇]

📖 简单选择排序

📖 堆排序

📕 归并类排序:数据结构与算法之排序算法-归并排序-CSDN博客

📖 归并排序

📚 线性时间非比较

📕 非比较类排序:数据结构与算法之排序算法-(计数,桶,基数排序)-CSDN博客

📖 计数排序

📖 桶排序

📖 基数排序

一、选择排序

稳定性:不稳定

时间复杂度:O(n^2)

额外空间复杂度:O(1)

选择排序是排序算法中最简单直观的排序算法之一,还记得冒泡排序吗?在冒泡排序中,我们是通过多次遍历数组,然后将此次遍历中最大的元素放到遍历范围的最后,选择排序和冒泡排序有一些相似之处:

冒泡排序的核心思想:不断寻找最大的元素并放到最后。
选择排序的核心思想:不断寻找最小的元素并放到最前。

① 选择排序(循环嵌套)

📚 算法思想

选择排序:通过两层循环,外层循环(int i = 0;i < len - 1;i++)代表从 i 开始,进行内层循环(int j = i + 1;j < len;j++)来寻找此次循环中的最小值,并将最小值放在 i 的位置~

图示

📖 代码示例

    public static void selectionSort(int[] arr){
        int len = arr.length;
        for(int i = 0;i < len - 1;i++){
            int minIndex = i;
            for(int j = i + 1;j < len;j++){
                if(arr[j] < arr[minIndex]){
                    minIndex = j;
                }
            }
            swap(arr,i,minIndex);
        }
    }

② 选择排序(双指针)

📚 算法思想

通过每次迭代同时找到当前范围内的最大值和最小值,并且将它们分别放到数组的两端,这样可以减少直接插入排序算法的迭代次数,做到提高效率(但其实没卵用...)

使用两个指针left和right,分别指向数组的起始位置和结束位置
每次迭代中,找到当前范围内[left,right]的最小值和最大值
将最小值放到left位置,将最大值放到right位置
然后缩小范围,left++,right--,直到left和right相遇。

📖 代码示例

    public static void selectSort2(int[] array){
        int left = 0;
        int right = array.length - 1;
        while(left < right){
            int minIndex = left;
            int maxIndex = left;
            System.out.println(Arrays.toString(array));
            for(int i = left + 1;i <= right;i++){
                if(array[minIndex] > array[i]){
                    minIndex = i;
                }
                if(array[maxIndex] < array[i]){
                    maxIndex = i;
                }
            }
            swap(array, left, minIndex);
            if(left == maxIndex){
                maxIndex = minIndex;
            }
            swap(array, right, maxIndex);
            left++;
            right--;
        }
    }

(可以实现一下用来练习自己的代码能力,实际应用的话还是算了,时间复杂度为O(n^2)不说,还不具有稳定性,代码长度甚至可以和优化过的快速排序一拼了也是难绷...连冒泡排序都不如...)

二、堆排序

稳定性:不稳定

时间复杂度:O(n logn)

额外空间复杂度:O(1)

堆排序的时间复杂度和快速排序一样,也是O(n logn),这是一种非常快速的排序了,并且它的额外空间复杂度为O(1),这也使得它在实际应用中也比较广泛。

📚 算法思想

堆排序的思想也是很简单的,在之前我们学习过"优先级队列",也可以分为"大根堆""小根堆"

不清楚什么是"优先级队列",不认识"大根堆","小根堆"的可以去我之前的文章中进行学习:
Java-数据结构-优先级队列(堆)_java优先级队列获取大根堆-CSDN博客
Java-数据结构-优先级队列(堆的使用)-CSDN博客
而堆排序的实现,就是以堆中的各种方法组合起来实现的:

首先,我们需要先将数组创建成一个"大根堆",这样我们就能够做到轻易地获取数组中的最大元素。

然后对这个"大根堆"的堆顶元素(最大元素)不断的放到最后,并进行删除操作(假意的删除,其实只是在后续操作中不再访问该元素),这样直到最后,我们就能得到一个升序数组。

在这个过程中,我们需要实现"创建大根堆""向下调整"的方法,而这些方法在上面两篇博客链接中也有详细的讲解,可以移步到上述两篇博客中进行学习~

图示

📖 代码示例

    public void heapSort(int[] array){
        //构造一个大根堆
        createHeap(array);
        int len = array.length;
        for(int i = len - 1;i > 0;i--){
            //将array[0]放到最后(最大的数放到最后)
            swap(array,0,i);
            //向下调整,再次变成大根堆(堆到后面的大数不再调整)
            siftDown(array,0,i);
        }
    }
    public void createHeap(int[] array){
        int index = array.length;
        //从最后一个父结点开始,依次将父结点向前进行向下调整
        for(int parent = (index - 1 - 1) / 2;parent >= 0;parent--){
            siftDown(array,parent,index);
        }
    }
    public void siftDown(int[] array,int parent,int len){
        int child = 2 * parent + 1;
        while(child < len){
            if(child + 1 < len && array[child + 1] > array[child]){
                child = child + 1;
            }
            if(array[child] > array[parent]){
                swap(array,child,parent);
                parent = child;
                child = parent * 2 + 1;
            }else {
                break;
            }
        }
    }

那么这篇关于选择排序的文章到这里就结束啦,作者能力有限,如果有哪里说的不够清楚或者不够准确,还请各位在评论区多多指出,我也会虚心学习的,我们下次再见啦

相关文章:

  • APP端弱网模拟与网络测试:如何确保应用在各种网络环境下稳定运行
  • 【动态规划】斐波那契数列模型
  • OpenCV 模板匹配
  • 算法-链表篇03-反转链表
  • EasyX学习笔记1:线条
  • C# struct, class的区别
  • 算法与数据结构(除自身以外数组的乘积)
  • 第2章:进阶格式与结构化元素
  • 如何利用PLM软件有效地推进制造企业标准化工作?
  • 1.综述 Google 的软件工程读书笔记
  • Golang Model 字段自动化校验设计
  • WEB安全--SQL注入--常见的注入手段
  • cv2.Sobel
  • 构建现代微服务安全体系:Spring Security、JWT 与 Spring Cloud Gateway 实践
  • 如何在 IntelliJ IDEA 中使用 Bito AI 插件
  • C++编程,#include <iostream>详解,以及using namespace std;作用
  • Android的Activity生命周期知识点总结,详情
  • ML.Net二元分类
  • spring boot 对接aws 的S3 服务,实现上传和查询
  • vue3.x 自定义hook函数详细解读
  • 以开放促发展,以发展促开放,浙江加快建设高能级开放强省
  • 中国新闻发言人论坛在京举行,郭嘉昆:让中国声音抢占第一落点
  • 警方通报男子广州南站持刀伤人:造成1人受伤,嫌疑人被控制
  • 南方降水频繁暴雨连连,北方高温再起或现40°C酷热天气
  • 观察|本轮印巴冲突或促使印度空军寻求更先进战机
  • 阿坝州委书记徐芝文已任四川省政府党组成员