详解七大排序算法

news2024/11/17 19:51:38

对于排序算法,是我们在数据结构阶段,必须要牢牢掌握的一门知识体系,但是,对于排序算法,里面涉及到的思路,代码……各种时间复杂度等,都需要我们,记在脑袋瓜里面!!尽量一丢丢不要出现差错!面试所必备的精彩提问!!

言归正传:对于排序,我们首先需要知道的是:排序的概念!!

排序的概念!

所谓的排序,,就是使一串记录,按照其中的某个或者某些关键字的大小,递增递减的排序起来的操作!!

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍然在r[j]之前,这种排序算法是稳定的,否则是不稳定的!!

就比如:9  5  2  7  3  6  4  5  8  0 这些数据而言!

内部排序:数据元素部分放在内存的排序

外部排序:数据元素不能同时放在内存中,根据排序过程的要求不同,在内存与外存之间移动数据的排序(要排序的数据,在内存中放不下!!)

下面笔者就以七种常见的排序算法为列,来带大家走进排序!!(直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序

1.插入排序:

插入排序:把待排序的记录按照其关键码值的大小,逐个插入到一个已经排序好的有序序列中,直到所有的记录插完为止,从而得到一个新的有序序列(扑克牌)

下面请看笔者的代码:

    public static void insertSort(int[] arr){//对传入的数组进行排序
        for (int i = 1; i<arr.length; i++){
            for (int j = i-1; j>=0; j--){
                if(arr[j]>arr[j+1]){//稳定的
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }else
                    break;
            }
        }
        System.out.println(Arrays.toString(arr));
    }


    public static void main(String[] args) {
        int[] array={12,56,32,67,10,19,4};
        insertSort(array);
    }

2.希尔排序

希尔排序的思想:先选定一个整数,把待排序文件中的所有记录分成多个组,所有距离为一样的放在同一个组内,并对每一组的记录进行插入排序,取重复上述分组和排序的工作,当达到=1时,所有记录在统一组内排序好(先分组,5组,3组,最后为1组)

假设初始的数据为: 9  1  2  5  7  4  8  6  3  5  

那么,我们有着一下 的简单排序过程:

经过上述的过程,我们可以看出:组数越多,每组进行排序的数据越少!(两两交换(使用插入排序)越有序越快),组数越少,每组数据越多(数据在慢慢变得有序)

那么,我们对于希尔排序,有着一下的几点总结:

  1. 希尔排序是对直接插入排序算法的优化!

  1. gap>1时,都是预排序,目的是让数组接近有序,当gap=1时,数组已经接近有序了,这样就会很快,这样整体而言,可以达到优化的效果,我们实现后可以进行性能测试的对比!

  1. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中,给出的希尔排序的时间复杂度不固定!

有了上述的思考,我们接下来就该实现一下代码了:

    public static  void shellSort(int[] array){
        int gap=array.length;//分组
        while (gap>1){
            shell(array,gap);
            gap=gap/2;
        }
        //整体进行插入排序,此时gap=1
        shell(array,1);
    }

    //插入排序
    public static void shell(int[] array,int gap){
        for (int i = 0; i <array.length; i++) {
            int tmp=array[i];
            int j=i-gap;
            for(;j>=0;j=j-gap){
                if (array[j]>tmp){
                    array[j+gap]=array[j];
                }else {
                    break;
                }
            }
            array[j+gap]=tmp;
        }
    }

    public static void main(String[] args) {
        int[] array={12,56,32,67,10,19,4};
        shellSort(array);
        System.out.println(Arrays.toString(array));
    }

3.选择排序

在了解选择排序之前,我们需要知道的是:

选择排序的思想:每一次从待排序的数据元素中选出最小(最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完,直接选择排序!

第一次从R[0]到R[n-1]中选出最小值,与R[0]进行交换,第二次从R[1]到R[n-1]中选出最小值与R[1]交换……,以此类推,从而得到从小到大的有序排序

经过上面的简单分析,我们可以得出下列的有效代码:

   public static void selectSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            
            for (int j = i + 1; j < array.length; j++) {
                if (array[j] < array[minIndex]) {
                    minIndex = j;
                    //minIndex保存最小数据的下标值!
                }
            }
            swap(array, i, minIndex);
        }
    }
    private static void swap(int[] array,int i,int j){
        int tmp=array[i];
        array[i]=array[j];
        array[j]=tmp;
    }

    public static void main(String[] args) {
        int[] array={12,56,32,67,10,4};
        selectSort(array);
        System.out.println(Arrays.toString(array));
    }

4.堆排序

对于堆排序,是指利用堆积树(堆),这种数据结构所设计的一种排序算法,它是一种选择排序,通过堆来进行选择数据

需要注意的是:排升序建大堆,排降序建小堆!!

那么,根据笔者之前的堆排序的环节:https://blog.csdn.net/weixin_64308540/article/details/129217324?spm=1001.2014.3001.5502我们可以有着一下的简单代码:

   public static void heapSort(int[] array){
        createBigHeap(array);//创建一个大根堆
        int end=array.length-1;
        while (end>0){//等于0的时候就不换了
            swap(array,0,end);//交换
            shiftDown(array,0,end);//向下调整
            end--;
        }
    }

    private static void createBigHeap(int[] array){
        //建立大根堆从最后一颗子树开始
        for (int parent = (array.length-1-1)/2; parent >=0 ; parent--) {
            shiftDown(array,parent,array.length);
            //array,length是指结束位置
        }
    }

    //向下调整
    private static void shiftDown(int[] array,int parent,int len){
        int child=2*parent+1;
        while (child<len){//至少有左孩子
            if (child+1<len && array[child]<array[child+1]){//有右孩子
                //此时child是左孩子最大值的下标
                child++;
            }
            if (array[child]>array[parent]){
                swap(array,child,parent);//交换
                parent=child;
                child=2*parent+1;
            }else {
                break;
            }
        }
    }

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

    public static void main(String[] args) {
        int[] array={12,56,32,67,10,4};
        heapSort(array);
        System.out.println(Arrays.toString(array));
    }

5.交换排序

对于交换排序,我们在之前就已经有过接触,其实就是最简单的冒泡排序

交换排序的基本思想:所谓交换就是根据序列中的两个记录键值的比较结果,交换这两个记录在序列中的位置!

交换排序的特点:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动

下面笔者就以冒泡排序来进行书写代码:

方法1:


    public static void bubblesort2(int[] array ) {
        //趟数
        for (int i = 0; i < array.length-1; i++) {
            //每趟执行的次数
            boolean flg=false;
            for(int j=0;j<array.length-1-i;j++) {
                if(array[j]>array[j+1]) {
                    int tmp=array[j+1];
                    array[j+1]=array[j];
                    array[j]=tmp;
                }
                flg=true;
            }
            if(flg==false) {
                return ;
            }
        }
    }

    public static void main(String[] args) {
        int[] array={1,29,10,36,5,21,46,3,6};
        bubblesort2(array);
        System.out.println(Arrays.toString(array));
    }

方法2:

    public static void bubbleSort2(int[] array){
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array.length-1-i; j++) {
                if (array[j]>array[j+1])
                    swap(array,j,j+1);
            }
        }
    }


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

    public static void main(String[] args) {
        int[] array={12,56,32,67,10,19,4};
        bubbleSort2(array);
        System.out.println(Arrays.toString(array));
    }

在上述代码中,方法1是对方法2的简单优化!!

在方法1中,我们通过一个:boolean flg=false;来优化了代码!!原因在于,在进行冒泡排序的时候,可能对于一串数据,排到一半就有序了,那么,在没有优化之前,肯定还得一个一个尝试去遍历,但是,在优化以后,可以节约时间!!

6.快速排序

快速排序的思想:任取待排序元素序列中的某元素一般是第一个元素),作为基准值,按照该排序码,将待排序的集合分为两个子序列,左子序中的所有元素均小于基准值,右子序中的所有元素均大于基准值,然后最左右子序列都重复该过程,直到所有的元素都排序在相应的位置为止!!

对于上述的简单思想,我们有着挖坑法Hoare法

下面我们先讲解一下挖坑法

先将第一个数据存放在一个临时变量key中,形成一个坑位!

  1. 设置两个变量i,j,排序开始的时候,i=0,j=N-1!

  1. 以第一个数组元素作为关键数据,赋值给key,即key=A[0]!

  1. 从j开始向前搜素,即由后开始向前搜素(j--),找到第一个小于key的值A[j],将A[j]与A[i]的值进行交换!

  1. 从i开始向后搜素,即由前开始向后搜素(i++),找到第一个大于key的值A[i],将A[i]与A[j]的值交换!

  1. 重复步骤3,4,直到i==j为止

对于上述的思路,我们可以用递归来实现!!

package zyh.example.demo.algorithm.kuaisupaixu;
 
import java.util.Arrays;
 
/**
* @ClassName KuaiPai13
* @Author zhangyonghui
* @Description
* @Date 2022/3/29 11:26
* @Version 1.0
**/
public class KuaiPai13 {
 
  public static void main(String[] args) {
        int[] arr = new int[]{4, 7, 6, 5, 3, 2, 8, 1};
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
  }
 
  /**
   * 快速排序--挖坑法
   * @param arr 数组
   * @param startIndex 左边界索引
   * @param endIndex 右边界索引
   */
  public static void quickSort(int[] arr, int startIndex, int endIndex) {
        // 递归结束条件:startIndex大等于endIndex的时候
        if (startIndex >= endIndex) {
              return;
        }
        // 得到基准元素位置
        int pivotIndex = partition(arr, startIndex, endIndex);
        // 用分治法递归数列的两部分
        quickSort(arr, startIndex, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, endIndex);
  }
 
  /**
   * 具体每一轮的快速排序:
   * @param arr 数组
   * @param startIndex 左边界索引
   * @param endIndex 右边界索引
   * @return 返回基准值的位置,此时基准值左边的元素都小于基准值,基准值右边的元素都大于基准值
   */
  private static int partition(int[] arr, int startIndex, int endIndex) {
        // 取第一个位置的元素作为基准元素
        int pivot = arr[startIndex];
        // 初始化坑的位置,初始等于pivot基准值的位置
        int kengIndex = startIndex;
        //初始化左右游标/指针
        int leftYb = startIndex;
        int rightYb = endIndex;
        //大循环在左右指针重合时结束
        while ( leftYb<rightYb ) {
              //right指针从右向左进行比较
              // leftYb<rightYb ,左游标永远小于右游标,是遍历元素并发生元素变动的前提:
              while ( leftYb<rightYb) {
                    // 先遍历右边,
                    //  如果元素大于基准值--右游标左移:
                    if (arr[rightYb] >= pivot) {
                          rightYb--;
                    }else{ //如果右边的当前元素小于基准值了,那么将该元素填入坑中,该元素本来的位置成为新的坑;
                          arr[kengIndex] = arr[rightYb];
                          kengIndex = rightYb;
                          leftYb++;
                          break;
                    }
              }
              //再遍历左边,
              // leftYb<rightYb ,左游标永远小于右游标,是遍历元素并发生元素变动的前提:
              while (leftYb<rightYb) {
                    //如果元素小于基准值--左游标右移,
                    if (arr[leftYb] <= pivot) {
                          leftYb++;
                    }else{  //如果左边的当前元素大于基准值了,那么将该元素填入坑中,该元素本来的位置成为新的坑;
                          arr[kengIndex] = arr[leftYb];
                          kengIndex = leftYb;
                          rightYb--;
                          break;
                    }
              }
        }
        //跳出了大循环,说明此时此刻左右游标是重合的,这时将基准值放在重合位置(最后一个坑),
        // 此时,基准值左边的元素都小于基准值,基准值右边的元素都大于基准值,这一轮交换宣告结束;
        arr[kengIndex] = pivot;
        return kengIndex;
  }
 
  
}

接下来进入Hoare法

right找到比基准小的停下来,left找到比基准大的停下来,进行比较,循环往复,最后当right==left的时候,将此时对应的值与基准进行比较!

请看笔者代码:

public class Main {
    static int[] a= {5, 3, 1, 9, 8, 2, 4, 7};
    public static void main(String[] args) {
        fastsort(0, a.length-1);
 
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i] + " ");
        }
    }
 
    private static int Hoare(int l, int r) {
        int p = a[l];
        int i = l-1;
        int j = r+1 ;
 
        while (true) {
            do {
                j--;
            } while (a[j] > p);
 
            do {
                i++;
            } while (a[i] < p);
 
            if (i < j) {
                int temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            } else
                return j;
        }
    }
    private static void fastsort(int l, int r) {
        if (l < r) {
            int s = Hoare(l, r);
            fastsort(l, s);
            fastsort(s+1, r);
        }
    }
}

7.归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用,将已有序的子序列合并,得到完全有序的序列,即,先使每个子序列有序,再使子序列断间有序!

主要的思路及其过程,如下图所示:

那么,接下来请看代码吧!!(递归实现)

    //递归实现
public static void mergeSort(int[] array){
        mergeSortFunc(array,0, array.length);
    }
    
    private static void mergeSortFunc(int[] array,int left,int right){
        if (left>=right){
            return;
        }
        //分解
        int mid=(left+right)/2;
        mergeSortFunc(array,left,mid);
        mergeSortFunc(array,mid+1,right);
        merge(array,left,right,mid);//合并
    }
    
    private static void merge(int[] array,int start,int end,int mid){
        int s1=start;
        int s2=mid+1;
        
        int[] tmp=new int[end-start+1];//申请一个数组
        int k=0;//tmp数组下标
        while (s1<=mid && s2<=end){
            if (array[s1]<= array[s2]){
                tmp[k++]=array[s1++];
            }else {
                tmp[k++]=array[s2++];
            }
        }
        while (s1<=mid){
            tmp[k++]=array[s1++];
        }
        while (s2<=end){
            tmp[k++]=array[s2++];
        }
        for (int i = 0; i < tmp.length; i++) {
            array[i+start]=tmp[i];
        }
    }

感兴趣的老铁,可以看一下非递归实现的:

//非递归
    public static void mergeSort2(int[] array){
        int gap=1;
        while (gap<array.length){
            for (int i = 0; i < array.length; i++) {
                int left=i;
                int mid=left+gap+1;
                if (mid>= array.length){
                    mid=array.length-1;
                }
                int right=mid+gap;
                if (right>=array.length){
                    right=array.length-1;
                }
                merge(array,left,right,mid);
            }
            gap=gap*2;
        }
    }

七大排序算法大致就到此结束了!!拜拜!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/390381.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode每日一题】——680.验证回文串 II

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 贪心算法 二【题目难度】 简单 三【题目编号】 680.验证回文串 II 四【题目描述】 给你一个字…

终端仿真器、协议分析器和 IO 监视器:IO Ninja 5.3.1 Crack

欢迎使用 IO Ninja 您的一站式终端仿真器、协议分析器和 IO 监视器 IO Ninja是一款专业的一体化终端仿真器、嗅探器和协议分析器。IO Ninja 是高度模块化的&#xff0c;并且具有适用于您可能跨越的大多数传输和协议的插件——网络&#xff08;、、、、、等&#xff09;、串行&…

实验3 设计模式实验2

实验内容: 1. 某Web 性能测试软件中包含一个虚拟用户生成器(Virtual User Generator)。 为了避免出现生成的虚拟用户数量不一致&#xff0c;该测试软件在工作时只允许启动唯一 一个虚拟用户生成器。采用单例模式设计该虚拟用户生成器&#xff0c;绘制类图并使用饿 汉式单例、双…

汇编语言程序设计(四)之汇编指令

系列文章 汇编语言程序设计&#xff08;一&#xff09; 汇编语言程序设计&#xff08;二&#xff09;之寄存器 汇编语言程序设计&#xff08;三&#xff09;之汇编程序 汇编指令 1. 数据传输指令 指令包括&#xff1a;MOV、XCHG、XLAT、LEA、LDS、LES、PUSH、POP、PUSHF、LA…

关闭应用程序遥测,禁止Windows收集用户信息

目录 1. 先创建还原点&#xff0c;防止意外 2. 界面设置 3. 服务 (1) GPEdit.msc - 本地计算机策略 - 计算机配置 - 管理模板 - Windows 组件 - 应用程序兼容性 - 关闭应用程序遥测 - 已启用 (2) GPEdit.msc - 本地计算机策略 - 计算机配置 - 管理模板 - Windows 组件 - 数…

aws apigateway 使用restapi集成lambda

参考资料 代理集成&#xff0c;https://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html非代理集成&#xff0c;https://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/getting-started-…

Android 面试必备:高工必问Binder机制~

面试可能会问到的问题 从IPC的方式问到Binder的优势为什么zygote跟其他服务进程的通讯不使用BinderBinder线程池和Binder机制 等等这些问题都是基于你对Binder的理解还有对其他IPC通讯的理解 IPC方式有多少种 传统的IPC方式有Socket、共享内存、管道、信号量等安卓特有的是Bi…

Spring AOP —— 详解、实现原理、简单demo

目录 一、Spring AOP 是什么&#xff1f; 二、学习AOP 有什么作用&#xff1f; 三、AOP 的组成 3.1、切面&#xff08;Aspect&#xff09; 3.2、切点&#xff08;Pointcut&#xff09; 3.3、通知&#xff08;Advice&#xff09; 3.4、连接点 四、实现 Spring AOP 一个简…

linux系统安装学习

文章目录一、系统安装二、命令格式和帮助三、文件目录操作命令创建目录四、cat查看文件内容、合并文件sudo获得root权限总结一、系统安装 二、命令格式和帮助 三、文件目录操作命令 ls查看目录文件 -a 显示隐藏的文件 -l 以列表的形式显示 -h 以人性化的方式显示文件内容大小 …

【java】Java 集合框架

文章目录集合框架体系如图所示集合接口集合实现类&#xff08;集合类&#xff09;集合算法如何使用迭代器遍历 ArrayList遍历 Map如何使用比较器总结早在 Java 2 中之前&#xff0c;Java 就提供了特设类。比如&#xff1a;Dictionary, Vector, Stack, 和 Properties 这些类用来…

【Maven】P4 生命周期与插件

Maven 生命周期与插件项目构建生命周期clean 生命周期default 构建生命周期site 构建生命周期插件项目构建生命周期 Maven 生命周期描述的是一次构建过程经历了多少个事件。 Maven 对构建生命周期划分为3套&#xff1a; clean&#xff1a;清理工作&#xff1b;default&#…

1.4 条件概率与乘法公式

1.4.1 条件概率在实际问题中&#xff0c;除了直接考虑某事件 B 发生的概率P(B)外,有时还会碰到这样的问题&#xff0c;就是“在事件A 已经发生的条件下,事件B 发生的概率”。一般情况下,后概率与前一概率不同&#xff0c;为了区别,我们常把后者称为条件概率&#xff0c;记为P(B…

一文带你入门angular(中)

一、angular中的dom操作原生和ViewChild两种方式以及css3动画 1.原生操作 import { Component } from angular/core;Component({selector: app-footer,templateUrl: ./footer.component.html,styleUrls: [./footer.component.scss] }) export class FooterComponent {flag: b…

tftp、nfs 服务器环境搭建

目录 一、认识 tftp、nfs 1、什么是 tftp&#xff1f; 2、什么是 nfs&#xff1f; 3、tftp 和 nfs 的区别 二、tftp的安装 1、安装 tftp 服务端 2、配置 tftp 3、启动 tftp 服务 三、nfs 的安装 1、安装 nfs 服务端 2、配置 nfs 3、启动 nfs 服务 一、认识 tftp、…

3D目标检测(毕业设计+代码)

概述 3d Objectron是一种适用于日常物品的移动实时3D物体检测解决方案。它可以检测2D图像中的物体&#xff0c;并通过在Objectron数据集上训练的机器学习&#xff08;ML&#xff09;模型估计它们的姿态. 下图为模型训练后推理的结果&#xff01; ​ 算法 我们建立了两个机器…

web项目的初始化

Tomcat 安装配置 Tomcat 官方站点&#xff1a;Apache Tomcat - Welcome! 。 安装 得到下载的安装包&#xff08;一般是 zip 文件&#xff09;&#xff0c;并解压到你指定的目录&#xff08;建议不要解压在 c 盘&#xff09;&#xff1b;&#xff08;这里以 windows10 系统为例…

网上电子商城的设计与实现

技术&#xff1a;Java、JSP等摘要&#xff1a;21 世纪以来&#xff0c;人类经济高速发展&#xff0c;人们的生活发生了日新月异的变化&#xff0c;特别是计算机的应用及普及到经济和社会生活的各个领域。在消费领域&#xff0c;网上购物已经成为大众所接受的一种新型的消费方式…

javaEE初阶 — 如何用 HTML 编写一个简易代码

文章目录html1. 建立一个文本文档的方式编写2. 标签的方式编写3. 补充&#xff1a;更改后缀的方式4. 如何使用 VS Code 来编写一个 html 代码4.1 VS Code 的下载4.2 VS Code 的使用html html 用来描述网页的骨架&#xff0c;这是一个非常有特点的 标签化 的语言。 下面来写一个…

分布式对象存储——Apache Hadoop Ozone

前言 本文隶属于专栏《大数据技术体系》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见大数据技术体系 1. 概述 Ozone是Apache Hadoop项目的子项目&#xf…

MySQL下载安装以及环境配置教程

目录MySQL 下载MySQL 安装配置环境变量MySQL 下载 进入官方网站 https://www.mysql.com/ 点击 DOWNLOADS 进入下载页面 免费版本点击下方的 MySQL Community (GPL) Downloads 点击 MySQL Community Server 点击 Go to Download Page 进入下载页面 点击 Download 点击 No thank…