排序算法总结

news2024/11/27 7:36:25

排序算法

排序算法可以分为内部排序和外部排序
内部排序是数据记录在内存中进行排序
外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序希尔排序选择排序冒泡排序归并排序快速排序堆排序基数排序等。
在这里插入图片描述
在这里插入图片描述

关于时间复杂度

平方阶 (O(n2)) 排序 各类简单排序:直接插入、直接选择和冒泡排序。

线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序;

O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 希尔排序

线性阶 (O(n)) 排序 基数排序,此外还有桶、箱排序。

关于稳定性

稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。

不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。

名词解释:

n:数据规模
k:"桶"的个数
In-place:占用常数内存,不占用额外内存
Out-place:占用额外内存
稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同

1.冒泡排序

public class BubbleSort {
    public static void main(String[] args) {
        int[] array = {5,9,7,4,1,3,2,8};
        bubble(array);
    }
 
    
 
    public static void bubble(int[] array){
        for (int j = 0; j < array.length - 1; j++) {
            //一轮冒泡
            boolean swapped = false; //表示是否发生了交换 false表示没有发生交换
            for (int i = 0; i < array.length - 1 - j; i++) {
                if (array[i] > array[i+1]) {
                    swap(array, i, i+1);
                    swapped = true;
                }
            }
            
            if (!swapped) {//数组中的元素没有发生交换,直接退出循环
                break;
            }
            System.out.println("第"+(j+1)+"轮冒泡:"+ Arrays.toString(array));
        }
    }
 
    public static void swap(int[] array,int i,int j){//将数组中下标为i和j的元素分别交换位置
        int t = array[i]; //先将下标为 i 的元素取出来放进缓存区
        array[i] = array[j];//将下标为 j 的元素放到原先下标为 i 的位置
        array[j] = t; //将下标为 i 的元素 从缓存区里取出来放入 原先下标为 j 的位置
    }
 
}
[5, 7, 4, 1, 3, 2, 8, 9]
[5, 4, 1, 3, 2, 7, 8, 9]
[4, 1, 3, 2, 5, 7, 8, 9]
[1, 3, 2, 4, 5, 7, 8, 9]
[1, 2, 3, 4, 5, 7, 8, 9]
[1, 2, 3, 4, 5, 7, 8, 9]

2.选择排序

public class SelectionSort {
    public static void main(String[] args) {
        int[] array = {5,3,7,2,1,9,8,4};
        selection(array);
    }
 
    private static void selection(int[] array){
        for (int i = 0; i < array.length - 1; i++) {//i 代表每轮选择最小元素要交换到的目标索引
            int minIndex = i; // 代表最小元素的索引
            for (int j = minIndex + 1; j < array.length; j++) { //假定下标为 0 的元素为最小,所以循环次数为数组的长度
                if (array[minIndex] > array[j]) {
                    minIndex = j; //更新最小下标
                }
            }
            if (minIndex != i) {  //如果最小下标发生变化,则更换元素的位置
                swap(array, minIndex, i);
            }
            System.out.println(Arrays.toString(array));
        }    
    }
 
    public static void swap(int[] array,int i,int j){//将数组中下标为i和j的元素分别交换位置
        int t = array[i]; //先将下标为 i 的元素取出来放进缓存区
        array[i] = array[j];//将下标为 j 的元素放到原先下标为 i 的位置
        array[j] = t; //将下标为 i 的元素 从缓存区里取出来放入 原先下标为 j 的位置
    }
 
}

[1, 3, 7, 2, 5, 9, 8, 4]
[1, 2, 7, 3, 5, 9, 8, 4]
[1, 2, 3, 7, 5, 9, 8, 4]
[1, 2, 3, 4, 5, 9, 8, 7]
[1, 2, 3, 4, 5, 9, 8, 7]
[1, 2, 3, 4, 5, 7, 8, 9]
[1, 2, 3, 4, 5, 7, 8, 9]

3.插入排序

public class InsertSort {
    public static void main(String[] args) {
        int[] array = {9,3,7,2,5,8,1,4};
        insert(array);
    }
 
    private static void insert(int[] array){
        for (int i = 1; i < array.length; i++) {//i 表示待插入元素的索引
            int t = array[i]; //表示待插入的元素值
            int j = i - 1; //表示已将排序区域的元素索引
            while (j >= 0) {
                if (t < array[j]) {//待插入的元素值 小于 已将排序区域的元素索引的值
                    array[j+1] = array[j];//将下标为 j 的元素向后移动一位
                }else { //待插入的元素值 大于 已经排序区域的元素索引的值
                    break; //找到插入位置,直接退出循环
                }
                j--; //依次向前进行比较,直到下标出现为负,退出循环
            }
            array[j+1] = t;//将待插入的元素值 插入到 空出的位置
            System.out.println(Arrays.toString(array));
        }
    }
}

[9, 3, 7, 2, 5, 8, 1, 4]
[3, 9, 7, 2, 5, 8, 1, 4]
[3, 7, 9, 2, 5, 8, 1, 4]
[2, 3, 7, 9, 5, 8, 1, 4]
[2, 3, 5, 7, 9, 8, 1, 4]
[2, 3, 5, 7, 8, 9, 1, 4]
[1, 2, 3, 5, 7, 8, 9, 4]
[1, 2, 3, 4, 5, 7, 8, 9]

4.希尔排序

package practise;

import java.util.Arrays;

public class ShellSort {
    public static void main(String[] args) {
        int[] array = {9, 3, 7, 2, 5, 8, 1, 4};
        shell(array);
    }

    private static void shell(int[] arr) {
        int length = arr.length;
        int temp;
        for (int step = length / 2; step >= 1; step /= 2) {
            for (int i = step; i < length; i++) {
                temp = arr[i];
                int j = i - step;
                while (j >= 0 && arr[j] > temp) {
                    arr[j + step] = arr[j];
                    j -= step;
                }
                arr[j + step] = temp;
                System.out.println(Arrays.toString(arr));
            }
        }
    }
}

[5, 3, 7, 2, 9, 8, 1, 4]  
[5, 3, 7, 2, 9, 8, 1, 4]
[5, 3, 1, 2, 9, 8, 7, 4]
[5, 3, 1, 2, 9, 8, 7, 4]
[1, 3, 5, 2, 9, 8, 7, 4]
[1, 2, 5, 3, 9, 8, 7, 4]
[1, 2, 5, 3, 9, 8, 7, 4]
[1, 2, 5, 3, 9, 8, 7, 4]
[1, 2, 5, 3, 7, 8, 9, 4]
[1, 2, 5, 3, 7, 4, 9, 8]
[1, 2, 5, 3, 7, 4, 9, 8]
[1, 2, 5, 3, 7, 4, 9, 8]
[1, 2, 3, 5, 7, 4, 9, 8]
[1, 2, 3, 5, 7, 4, 9, 8]
[1, 2, 3, 4, 5, 7, 9, 8]
[1, 2, 3, 4, 5, 7, 9, 8]
[1, 2, 3, 4, 5, 7, 8, 9]

5. 快速排序

5.1单边循环快排

public class QuickSort1 {
    public static void main(String[] args) {
        int[] array = {5,3,7,2,9,8,1,4};
        //3,5,7,2,9,8,1,4  3,2,7,5,9,8,1,4  3,2,1,5,9,8,7,4  3,2,1,4,9,8,7,5
        //3,2,1,4,9,8,7,5  1,2,3,4,9,8,7,5  1,2,3,4,5,8,7,9  1,2,3,4,5,7,8,9
        quick(array, 0, array.length-1);
    }
 
    //递归
    public static void quick(int[] array,int low,int high){
        if (low >= high) {
            return;
        }
        int p = partition(array, low, high); //表示  基准点元素所在的正确索引
        //确定左边分区范围
        quick(array,low,p-1);
        //确定右边分区范围
        quick(array, p+1, high);
    }
 
    //分区
    private static int partition(int[] array,int low,int high){ //low 表示左边界  high: 表示右边界
        int pv = array[high]; //选取最右边的元素为基准点元素
        int i = low;
        for (int j = low; j < high; j++) {
            if (array[j] < pv) {//下标小于基准点的元素
                swap(array, i, j); //将小于基准点的元素换到 下标为i 所在的位置
                i++;
            }
        }
        swap(array, high, i); //将基准点和 下标为i 的元素互换位置
        System.out.println(Arrays.toString(array)+"i="+i);
        //返回值表示基准点元素所在的正确索引,以此来确定下一轮的边界分区
        return i;
    }
 
    public static void swap(int[] array,int i,int j){//将数组中下标为i和j的元素分别交换位置
        int t = array[i]; //先将下标为 i 的元素取出来放进缓存区
        array[i] = array[j];//将下标为 j 的元素放到原先下标为 i 的位置
        array[j] = t; //将下标为 i 的元素 从缓存区里取出来放入 原先下标为 j 的位置
    }
}

[3, 2, 1, 4, 9, 8, 7, 5]i=3
[1, 2, 3, 4, 9, 8, 7, 5]i=0
[1, 2, 3, 4, 9, 8, 7, 5]i=2
[1, 2, 3, 4, 5, 8, 7, 9]i=4
[1, 2, 3, 4, 5, 8, 7, 9]i=7
[1, 2, 3, 4, 5, 7, 8, 9]i=5

5.2双边循环快排

public class QuickSort2 {
    public static void main(String[] args) {
        int[] array = {5,3,7,2,9,8,1,4};
        // 5,3,4,2,9,8,1,7  5,3,4,2,1,8,9,7  1,3,4,2,5,8,9,7
        // 1,3,2,4,5,8,9,7  1,2,3,4,5,8,9,7  1,2,3,4,5,8,7,9  1,2,3,4,5,7,8,9
        quick(array, 0, array.length-1);
    }
 
    //递归
    public static void quick(int[] array,int low,int high){
        if (low >= high) {
            return;
        }
        int p = partition(array, low, high); //表示  基准点元素所在的正确索引
        //确定左边分区范围
        quick(array,low,p-1);
        //确定右边分区范围
        quick(array, p+1, high);
    }
 
    //分区
    private static int partition(int[] array,int low,int high){ //low 表示左边界  high: 表示右边界
        int pv = array[low]; //选取最左边的元素为基准点元素
        int i = low; //i 开始位于左边界
        int j = high; // j 开位于右边界
        while (i < j){
            //j 从最右边的元素开始找 小于基准点的元素
            while (i < j && array[j] > pv) { // i < j -- 防止 i 和 j发生越界
                j--;
            }
            //i 从最左边的元素开始找 大于基准点的元素
            while (i < j && array[i] <= pv) { //array[i] <= pv -- i开始位于左边界,且 pv 为左边界的元素 如果不相等,就无法进入循环
                i++;
            }
            swap(array, i, j); // j 找到小于基准点的元素  i找到大于基准点的元素,两者位置发生互换
        }
        swap(array, low, j); //基准点 和 i(i和j相等) 互换,i 为 新的分区位置
        System.out.println(Arrays.toString(array) + "j=" + j);
        return j;
    }
 
    public static void swap(int[] array,int i,int j){//将数组中下标为i和j的元素分别交换位置
        int t = array[i]; //先将下标为 i 的元素取出来放进缓存区
        array[i] = array[j];//将下标为 j 的元素放到原先下标为 i 的位置
        array[j] = t; //将下标为 i 的元素 从缓存区里取出来放入 原先下标为 j 的位置
    }
}

[1, 3, 4, 2, 5, 8, 9, 7]j=4
[1, 3, 4, 2, 5, 8, 9, 7]j=0
[1, 2, 3, 4, 5, 8, 9, 7]j=2
[1, 2, 3, 4, 5, 7, 8, 9]j=6

6. 归并排序

在这里插入图片描述

在这里插入图片描述

public class MergeSort {
    public static void main(String[] args) {
        int[] array = {9,3,7,2,5,8,1,4};
        int[] answer = cut(array);

        System.out.println(Arrays.toString(answer));

    }

    public static int[] cut(int[]data){
        if(data.length == 1){//如果a的长度为1,表示数组只有一个元素,数组数据划分结束
            return data;
        }
        else {
            int leftArrLength = data.length / 2;//数组的元素个数一分为二,左边数组元素个数为元素组的一半
            int rightArrLength = data.length - leftArrLength;//右边数组元素个数为元素组个数-左边数组元素个数

            int [] left = new int[leftArrLength]; //被划分元素组左边,创建新数组为left
            int [] right = new int[rightArrLength];//被划分元素组右边,创建新数组为right

            for(int i = 0; i < leftArrLength; i++){//遍历数组元素放入left中
                left[i] = data[i];
            }

            for(int i=leftArrLength; i<data.length; i++){//遍历数组元素放入right中
                right[i-leftArrLength] = data[i];
            }
            System.out.println(Arrays.toString(left));
            System.out.println(Arrays.toString(right));
        return merge(cut(left), cut(right));//递归a数组中的元素,直到数组元素为1,之后进数组合并

        }

    }
    public static int[] merge(int[] leftArr, int[] rightArr) {//数组合并
        int finalArrsize = leftArr.length + rightArr.length;//新数组长度为左右两边数组合并的长度
        int[] finalArr = new int[finalArrsize];//创建新的数组,为合并后的数组
        int leftArrCounter = 0;//指针从0开始
        int rightArrCounter = 0;//指针从0开始
        int finalArrCounter = 0;//指针从0开始

        while (finalArrCounter < finalArrsize) {
            if (leftArrCounter >= leftArr.length) {
                finalArr[finalArrCounter] = rightArr[rightArrCounter];
                rightArrCounter++;
            } else if (rightArrCounter >= rightArr.length) {
                finalArr[finalArrCounter] = leftArr[leftArrCounter];
                leftArrCounter++;
            } else if (leftArr[leftArrCounter] < rightArr[rightArrCounter]) {
                finalArr[finalArrCounter] = leftArr[leftArrCounter];
                leftArrCounter++;
            } else {
                finalArr[finalArrCounter] = rightArr[rightArrCounter];
                rightArrCounter++;
            }
            finalArrCounter++;
        }

        return finalArr;
    }

}
[9, 3, 7, 2]
[5, 8, 1, 4]
[9, 3]
[7, 2]
[9]
[3]
[7]
[2]
[5, 8]
[1, 4]
[5]
[8]
[1]
[4]
[1, 2, 3, 4, 5, 7, 8, 9]

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

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

相关文章

Qt-OpenCV学习笔记--人脸识别

前言 本人从事机械设计12年&#xff0c;业余时间自学编程。 2022年4月6日&#xff0c;开始学习C#&#xff0c; 2022年9月7日&#xff0c;开始学习c和Qt&#xff0c; 2022年10月28日&#xff0c;开始学习OpenCV&#xff0c; 今天终于搞定了传说中的 人脸识别 &#xff0c;在…

spirngcloud的基本介绍与服务注册

1. 应用系统架构的演变 单应用架构 -> 应用服务器和数据库服务器分离 -> 应用服务器集群 -> 数据库压力变大&#xff0c;数据库读写分离 -> 引入缓存机制缓解数据库的压力 -> 数据库的水平/垂直拆分(数据库分库分表) -> 应用的拆分&#xff08;微服务&…

[附源码]计算机毕业设计绿色生活交流社区网站Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

GitLab搭建

以docker方式运行gitlab docker run --detach \--hostname gitlab.mczaiyun.top \--publish 8443:443 --publish 8090:80 --publish 8022:22 \--name gitlab \--restart always \--volume /root/gitlab/config:/etc/gitlab \--volume /root/gitlab/logs:/var/log/gitlab \--vo…

Elasticsearch入门(二)基本操作(索引、文档、映射)

数据格式 Elasticsearch 是面向文档型数据库&#xff0c;一条数据在这里就是一个文档。为了方便大家理解&#xff0c;我们将 Elasticsearch 里存储文档数据和关系型数据库 MySQL 存储数据的概念进行一个类比ES 里的 Index 可以看做一个库&#xff0c;而 Types 相当于表&#x…

【在Vue脚手架项目中使用qs框架】

目录 1. 安装qs框架 2. 在main.js中添加配置 1. 安装qs框架 在前端项目中&#xff0c;可以使用qs框架&#xff0c;实现“将对象转换为FormData格式的数据”。 首先&#xff0c;安装此框架&#xff1a; 如果没有权限进入C盘找到cmd的执行软件&#xff0c;用管理员启动&…

练习题(12-06)

目录 1.最小数 2.数天数 3.非常特殊的数 4.最大值路径 5.拆分质数 6.文件拷贝 7.除去重复单词 8.变成回文字符串 1.最小数 题目描述 请找到一个大于2022的最小数&#xff0c;这个最小的数转换成二进制后&#xff0c;最低的6个二进制全为0. 思路&#xff1a;枚举即…

[附源码]Python计算机毕业设计Django物业管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Java开发:反射机制

一、Java Reflection Reflection&#xff08;反射&#xff09;是java被视为动态语言的关键&#xff08;Java是静态语言&#xff0c;因为有了反射所以又被成为“准动态语言”&#xff09; 二、重点&#xff1a;一个类只有一个Class对象 三、反射的优缺点 优点&#xff1a;可…

【JAVA问题解决方案】02.Freemarker导出Excel超出上限分表解决方案

陈老老老板&#x1f9b8;&#x1f468;‍&#x1f4bb;本文专栏&#xff1a;Java问题解决方案&#xff08;都是一些常见的问题解决方案&#xff09;&#x1f468;‍&#x1f4bb;本文简述&#xff1a;本文讲一下有关Freemarker导出Excel分表的解决方案&#xff0c;超级详细。&a…

Tomcat7+ 弱口令 后台getshell漏洞

Tomcat7 弱口令 && 后台getshell漏洞 &#x1f349; shell 此环境来自vulhub工程&#xff1a; https://github.com/vulhub/vulhub 以下测试环境为ubuntu 20.04 &#x1f349;目录Tomcat7 弱口令 && 后台getshell漏洞环境准备弱密码登录war文件上传蚁剑连接…

SoftEther linux与windows使用

1、SoftEther简介 我们来先科普一下什么是SoftEther吧&#xff0c;SoftEther是由日本筑波大学的登大遊在硕士论文中提出的开源、跨平台、多重协议的虚拟专用网方案,其实我更看重的是他的内网穿透功能&#xff0c;下面来一张图片&#xff0c;说明它的强大。 SoftEther正确定的安…

【力扣】剑指offer第二天

剑指offer第二天[剑指 Offer 06. 从尾到头打印链表 - 力扣&#xff08;LeetCode&#xff09;]方法一代码方法二代码[剑指 Offer 24. 反转链表 - 力扣&#xff08;LeetCode&#xff09;]方法一代码方法二代码[剑指 Offer 35. 复杂链表的复制 - 力扣&#xff08;LeetCode&#xf…

日期功能组件(加上左右点击,更改月份)

要求效果&#xff1a; &#xff0c;直接可以显示年月&#xff0c;并且点击左右箭头可以更改月份 点击这个日期&#xff0c;可以选择。 最后实现效果&#xff1a; 实现&#xff1a; 先找一个插件&#xff0c;可以选择时间 <!-- 选择年月--><div class"form-…

SAP ARFCSTATE ARFCSDATA TRFCQOUT

SELECT count(1) FROM arfcsstate --18848155 20221122 清理前 -- 6582457 清理后 SELECT count(1) FROM ARFCSDATA a -- 81732430 202221122 清理前 -- 25064628 清理后 SELECT count(1) FROM TRFCQOUT t --18848095 202221122 …

面试必备:HashMap底层源码原来是这么简单(分析)

微信公众号&#xff1a;SteveCode 关注可了解更多的编程及开发经验。问题或建议&#xff0c;请公众号留言; 专注Java技术干货分享&#xff0c;Java技术、数据结构、相关工具、Spring全家桶、intellij idea…… 如果你觉得对你有帮助&#xff0c;欢迎赞赏 transient 发现了这个关…

re:Invent现场访谈:云计算如何重塑智能制造

众所周知&#xff0c;近年来包括中国和美国在内&#xff0c;世界上各个主要国家对制造业的关注度都在不断提升。也正因为如此&#xff0c;在2022亚马逊云科技re:Invent全球大会上&#xff0c;有关云计算技术在智能制造行业的应用&#xff0c;也理所当然地成为了诸多与会嘉宾关注…

【JMeter】线程组jp@gc - Stepping Thread Group(逐步线程组)

jpgc - Stepping Thread Group 逐步线程组 Action to be taken after a Sample error 发生sample错误时 Continue 继续 Start Next Thread Loop 开始新的线程 Stop Thread 停止线程 Stop Test 停止测试 Stop Test Now 立即停止测试 Threads Scheduling Parameters 线程调度…

STM32+雷龙SD NAND(贴片SD卡)完成FATFS文件系统移植与测试

一、前言 在STM32项目开发中&#xff0c;经常会用到存储芯片存储数据。 比如&#xff1a;关机时保存机器运行过程中的状态数据&#xff0c;上电再从存储芯片里读取数据恢复&#xff1b;在存储芯片里也会存放很多资源文件。比如&#xff0c;开机音乐&#xff0c;界面上的菜单图…

使用SpringBoot快速构建Web API

Dubbo 框架现在在国内的中小企业当中已经成为 Java 生态下服务化的事实标准&#xff0c;出现这种状态的原因很多&#xff0c;比如 Dubbo 框架设计优秀、文档和资料丰富、配置灵活、特性丰富等&#xff0c;但最主要的&#xff0c;我认为是 Java 开发人员对速度这一因素的痴迷。 …