【数据结构】常见七大排序总结

news2024/11/20 21:21:39

目录

一、插入排序:直接插入排序【稳定排序方法】

二、插入排序:希尔排序【不稳定排序方法】

三、选择排序:直接选择排序【不稳定排序方法】

四、选择排序:堆排序【不稳定排序方法】

五、交换排序:冒泡排序【稳定排序方法】

六、交换排序:快速排序【不稳定排序方法】

七、归并排序:归并排序【稳定排序方法】


前言

排序是计算机程序设计中的一种重要操作,其功能是对一个数据元素集合或序列重新排列成一个按数据元素某个相知有序的序列。排序分为两类:内排序和外排序。

 今天为大家总结一下,常见的七大排序:

一、插入排序:直接插入排序【稳定排序方法】

1.概述

1.1 插入排序,一般也被称为直接插入排序。

1.2 插入排序每次将一个待排序的记录,按其键字的大小插入到前面已排序好的记录序列中的适当位置,直到全部记录插入完成为止。

1.3  直接插入排序是一种最简单的排序方法,其基本操作是将一条记录插入到已排好的有序表中,从而得到一个新的、记录数量增1的有序表。

2. 算法实现:

2.1不带监视哨  

//【算法1】 不带监视哨的直接插入排序算法
public void insertSort() {
    RecordNode temp;
    int i, j;
    for (i = 1; i < this.curlen; i++) {		// n-1趟扫描
        temp = r[i];  						// 将待插入的第i条记录暂存在temp中
        for (j = i - 1; j >= 0 && temp.key.compareTo(r[j].key) < 0; j--) { 
            r[j + 1] = r[j];				// 将前面比r[i]大的记录向后移动
        }
        r[j + 1] = temp;          			// r[i]插入到第j+1个位置
        //System.out.print("第" + i + "趟: ");
        //display();
    }
}

2.2带监视哨

//【算法2】带监视哨的直接插入排序算法
public void insertSortWithGuard() {
 
    int i, j;
//        System.out.println("带监视哨的直接插入排序");
    for (i = 1; i <this.curlen; i++) {      //n-1趟扫描
        r[0] = r[i]; //将待插入的第i条记录暂存在r[0]中,同时r[0]为监视哨
        for (j = i - 1; r[0].key.compareTo(r[j].key) < 0; j--) { //将前面较大元素向后移动
            r[j + 1] = r[j];
        }
        r[j + 1] = r[0];          // r[i]插入到第j+1个位置
        System.out.print("第" + i + "趟: ");
        display(9);
    }
}

二、插入排序:希尔排序【不稳定排序方法】

1.概述

希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法

 2. 算法实现

//【算法3】希尔排序算法
public void shellSort(int[] d) { //d[]为增量数组
    RecordNode temp;
    int i, j;
    System.out.println("希尔排序");
    //控制增量,增量减半,若干趟扫描
    for (int k = 0; k < d.length; k++) {
        //一趟中若干子表,每个记录在自己所属子表内进行直接插入排序
        int dk = d[k];
        for (i = dk; i < this.curlen; i++) {
            temp = r[i];
            for (j = i - dk; j >= 0 && temp.key.compareTo(r[j].key) < 0; j -= dk) {
                r[j + dk] = r[j];
            }
            r[j + dk] = temp;
        }
        System.out.print("增量dk=" + dk + "  ");
        display();
    }
}

三、选择排序:直接选择排序【不稳定排序方法】

1.概述

  • 首先在所有记录中选出关键字值最小的记录,把它与第一个记录进行位置交换,

  • 然后在其余的记录中再选出关键字值次小的记录,与第二个记录进行位置交换。

  • 依次类推,直到所有记录排好序。

 2. 算法实现

//【算法】直接选择排序
public void selectSort() {
 //   System.out.println("直接选择排序");
    RecordNode temp; //辅助结点
    for (int i = 0; i < this.curlen - 1; i++) {//n-1趟排序
        //每趟在从r[i]开始的子序列中寻找最小元素
        int min = i;               //设第i条记录的关键字最小
        for (int j = i + 1; j < this.curlen; j++) {//在子序列中选择关键字最小的记录
            if (r[j].key.compareTo(r[min].key) < 0) {
                min = j;             //记住关键字最小记录的下标
            }
        }
        if (min != i) {    //将本趟关键字最小的记录与第i条记录交换
            temp = r[i];
            r[i] = r[min];
            r[min] = temp;
        }
        System.out.print("第" + (i + 1) + "趟: ");
        display();
    }
}

四、选择排序:堆排序【不稳定排序方法】

1.概述

堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

  • 大顶堆:每个节点的值都大于或者等于它的左右子节点的值。

  • 小顶堆每个节点的值都小于或者等于它的左右子节点的值。

  • 一般升序采用大顶堆,降序采用小顶堆

2.示意图

3.算法实现

基本思想:

1. 首先将这n条记录按关键字值的大小建立堆(称为初始堆),将堆顶元素r[0]与r[n-1]交换

2. 然后,将剩下的{r[0]..r[n-2]}序列调整成堆

3. 再将 r[0]与r[n-2]交换,再将剩下的{r[0]..r[n-3]}序列调整成堆

4. 如此反复,直到整个序列有序。

5. 这个过程称为堆排序
 

3.1 筛选法调整堆:算法

//【算法】将以筛选法调整堆算法
//将以low为根的子树调整成小顶堆,low、high是序列下界和上界
public void sift(int low, int high) {
    int i = low;                                //子树的根
    int j = 2 * i + 1;                         //j为i结点的左孩子
    RecordNode temp = r[i];
    while (j < high) {  //沿较小值孩子结点向下筛选
        if (j < high - 1 && r[j].key.compareTo(r[j + 1].key) > 0) {
            j++; //数组元素比较,j为左右孩子的较小者
        }
        if (temp.key.compareTo(r[j].key) > 0) { //若父母结点值较大
            r[i] = r[j];           //孩子结点中的较小值上移
            i = j;
            j = 2 * i + 1;
        } else {
            j = high + 1;          //退出循环
        }
    }
    r[i] = temp;                   //当前子树的原根值调整后的位置
//  System.out.print("sift  " + low + ".." + high + "  ");
//  display();
}

3.2堆排序:算法

//【算法】 堆排序算法
public void heapSort() {
   // System.out.println("堆排序");
    int n = this.curlen;
    RecordNode temp;
    // 从最后一个非叶子节点开始调整堆,直到根结点
    for (int i = n / 2 - 1; i >= 0; i--) {//创建堆
        sift(i, n);
    }
    System.out.println("堆构建完成");
    for (int i = n - 1; i > 0; i--) {//每趟将最小值交换到后面,再调整成堆
        // 第一个元素和无序中的最后一个交换
        temp = r[0];
        r[0] = r[i];
        r[i] = temp;
        sift(0, i);
    }
}

五、交换排序:冒泡排序【稳定排序方法】

1.概述

比较相邻的元素。如果第一个比第二个大,就交换他们两个。 

  • 将待排序的数组看成从上到下的存放,关键字较小的记录看成较轻的,关键字较大的记录看成较重的。

  • 较小关键字的记录,好像水中的气泡一样,向上浮

  • 较大关键字的记录,好像水中的石块一样,向下沉

  • 当所有的气泡都浮到了相应的位置,并且所有的石块都沉到了水中,排序就结束了

2.算法实现

//【算法】 冒泡排序算法
public void bubbleSort() {
//    System.out.println("冒泡排序");
    RecordNode temp;                                    // 辅助结点
    boolean flag = true;                                // 是否交换的标记
    for (int i = 1; i < this.curlen && flag; i++) {   // 有交换时再进行下一趟,最多n-1趟
        flag = false;                                   // 假定元素未交换
        for (int j = 0; j < this.curlen - i; j++) {     // 一次比较、交换
            if (r[j].key.compareTo(r[j + 1].key) > 0) { // 逆序时,交换
                temp = r[j];
                r[j] = r[j + 1];
                r[j + 1] = temp;
                flag = true;							//如果发生交换,记录
            }
        }
        System.out.print("第" + i + "趟: ");
        display();
    }
}

六、交换排序:快速排序【不稳定排序方法】

1.概述

  • 快速排序:Quick Sort

  • 通过一趟排序将要排序的记录分割成独立的两个部分,其中一部分的所有记录的关键字值都比另外一部分的所有记录关键字值小。

  • 然后再按此方法对这两部分记录分别进行快速排序。

  • 整个排序过程可以递归进行,以此达到整个记录序列变成有序

2.算法实现

2.1一趟快速排序

//【算法】一趟快速排序
//交换排序表r[i..j]的记录,使支点记录到位,并返回其所在位置
//此时,在支点之前(后)的记录关键字均不大于(小于)它
public int Partition(int i, int j) {
    RecordNode pivot = r[i];          //第一个记录作为支点记录
    System.out.println(i + ".." + j + ",  pivot=" + pivot.key + "  ");
    System.out.print("初始值:     ");
    int c = 0;
    display();
    while (i < j) {    //从表的两端交替地向中间扫描
        // 1.1 从后到前,寻找第一个比支点小的元素
        while (i < j && pivot.key.compareTo(r[j].key) <= 0) {
            j--;
        }
        // 1.2 将后面较小的元素,移到前面去
        if (i < j) {
            r[i] = r[j];   //将比支点记录关键字小的记录向前移动
            System.out.print("第"+(++c)+"次交换后:");
            display();
            i++;
        }
        // 2.1 从前到后,选择第一恶比支点大的元素
        while (i < j && pivot.key.compareTo(r[i].key) > 0) {
            i++;
        }
        // 2.2 将前面较大的元素,移到后面去
        if (i < j) {
            r[j] = r[i];   //将比支点记录关键字大的记录向后移动
            System.out.print("第"+(++c)+"次交换后:");
            display();
            j--;
        }
 
    }
    r[i] = pivot;         //支点记录到位
    System.out.print("一趟完成:   ");
    display();
    return i;             //返回支点位置
}

2.2 完整快排

//【算法】 递归形式的快速排序算法
//对子表r[low..high]快速排序
public void qSort(int low, int high) {
    if (low < high) {
        int pivotloc = Partition(low, high);   // 一趟排序,将排序表分为两部分
        qSort(low, pivotloc - 1);       // 低子表递归排序
        qSort(pivotloc + 1, high);      // 高子表递归排序
    }
}
 
//【算法完整快排】顺序表快速排序算法
public void quickSort() {
    qSort(0, this.curlen - 1);
}

七、归并排序:归并排序【稳定排序方法】

1.概述

归并排序是建立在归并操作上的一种有效,稳定的排序算法。是将合并得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。已有序的子序列

 归并排序:两个或两个以上有序表合并成一个新的有序表。

归并排序分类:

1. 二路归并排序

2. 多路归并排序

2.算法实现

2.1 两个相邻有序序列归并:算法

/**
 *
 * @param r 待排序的数组(多个有序子序列)
 * @param order 已经排序号的数组
 * @param h 第一个子序列开始的位置
 * @param m 第一个子序列结束的位置,第二个子序列开始的位置为m+1
 * @param t 第二个子序列结束的位置
 */
//【算法】两个有序序列的归并算法
//把r数组中两个相邻的有序表r[h]~r[m]和r[m+1]~r[t]归并为一个有序表order[h]~order[t]
public void merge(RecordNode[] r, RecordNode[] order, int h, int m, int t) {
    int i = h, j = m + 1, k = h;
    while (i <= m && j <= t) {                  // 将r中两个相邻子序列归并到order中
        if (r[i].key.compareTo(r[j].key) <= 0) {// 较小值复制到order中
            order[k++] = r[i++];
        } else {
            order[k++] = r[j++];
        }
    }
    while (i <= m) {                // 将前一个子序列剩余元素复制到order中
        order[k++] = r[i++];
    }
    while (j <= t) {                // 将后一个子序列剩余元素复制到order中
        order[k++] = r[j++];
    }
}

2.1 一趟归并:算法

//【算法】一趟归并算法
//把数组r[n]中每个长度为s的有序表两两归并到数组order[n]中
//s 为子序列的长度,n为排序序列的长度
public void mergepass(RecordNode[] r, RecordNode[] order, int s, int n) {
    System.out.print("子序列长度s=" + s + " ");
    int p = 0;  //p为每一对待合并表的第一个元素的下标,初值为0
    while (p + 2 * s - 1 <= n - 1) {  //两两归并长度均为s的有序表
        merge(r, order, p, p + s - 1, p + 2 * s - 1);
        p += 2 * s;
    }
    if (p + s - 1 < n - 1) {  //归并最后两个长度不等的有序表
        merge(r, order, p, p + s - 1, n - 1);
    } else {
        for (int i = p; i <= n - 1; i++) //将剩余的有序表复制到order中
        {
            order[i] = r[i];
        }
    }
}

2.1 二路归并: 算法

//打印方法
public void display(RecordNode[] arr) {    //输出数组元素
    for (int i = 0; i < arr.length; i++) {
        String str = arr[i].key.toString().length() == 1 ? "  " : " ";
        System.out.print(str + arr[i].key.toString());
    }
    System.out.println();
}




//【算法】2-路归并排序算法
public void mergeSort() {
    System.out.println("归并排序");
    int s = 1;                              // s为已排序的子序列长度,初值为1
    int n = this.curlen;
    RecordNode[] temp = new RecordNode[n];  // 定义长度为n的辅助数组temp
    while (s < n) {
        mergepass(r, temp, s, n);           // 一趟归并,将r数组中各子序列归并到temp中
        display(temp);                      // 打印temp临时数组
        s *= 2;                             // 子序列长度加倍,下一趟归并
        mergepass(temp, r, s, n);           // 将temp数组中各子序列再归并到r中
        display();                          // 打印r数组
        s *= 2;
    }
}

写到最后

四季轮换,已经数不清凋零了多少, 愿我们往后能向心而行,一路招摇胜!

🐋 你的支持认可是我创作的动力

💟 创作不易,不妨点赞💚评论❤️收藏💙一下

😘 感谢大佬们的支持,欢迎各位前来不吝赐教

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

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

相关文章

基于单片机MC9S12XS128的两轮自平衡小车设计

目 录 1.绪论 1 1.1研究背景与意义 1 1.2两轮自平衡车的关键技术 2 1.2.1系统设计 2 1.2.2数学建模 2 1.2.3姿态检测系统 2 1.2.4控制算法 3 1.3本文主要研究目标与内容 3 1.4论文章节安排 3 2.系统原理分析 5 2.1控制系统要求分析 5 2.2平衡控制原理分析 5 2.3自平衡小车数学…

总结一下flex布局

flex布局 传统布局方案是基于盒状模型&#xff0c;依赖 display position float 方式来实现&#xff0c;灵活性较差&#xff1b;Flex是Flexible Box的缩写&#xff0c;意为”弹性布局”。Flex可以简便、完整、响应式地实现多种页面布局 CSS3 弹性盒子是一种一维的布局&…

[Spring MVC3]MyBatis详解

本章重点讲述了MyBatis映射器&#xff0c;对数据层进行的操作&#xff0c;建议本篇文章和Spring Boot的持久层相互比较来看会更加收获颇多Spring Boot持久层技术 本文需要使用到MVC第一讲的模板格式与配置情况&#xff0c;全部代码已经放在此博客中&#xff0c;Spring MVC1 目…

修改设备管理器的COM端口名称

Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class{4d36e978-e325-11ce-bfc1-08002be10318}\0001] “InfPath”“oem53.inf” “InfSection”“CH341SER_Inst.NTamd64” “ProviderName”“wch.cn” “DriverDateData”hex:00,00…

计算机算法(二)——进入计算机世界

作者介绍&#xff1a; &#x1f4de;作者&#xff1a;小刘在C站 &#x1f4c0;每天分享课堂笔记 &#x1f339;夕阳下&#xff0c;是最美的绽放 瑞士著名的科学家Niklaus Wirth教授曾提出&#xff1a;数据结构算法程序。 数据结构是程序的骨 算法是程序的灵魂。 在生活…

【 C++11 】lambda表达式

目录 1、lambda表达式的引入 2、lambda表达式 lambda表达式的语法 lambda表达式捕捉列表说明 使用lambda表达式排序自定义类型 lambda表达式的底层原理 1、lambda表达式的引入 在C98中&#xff0c;如果想要对一个数据集合中的元素进行排序&#xff0c;可以使用std::sort方法&…

asp.net图书馆借阅归还系统

图书管理系统既是完整的知识定位系统&#xff0c;又是面向未来互联网发展的信息管理模式。图书管理系统&#xff0c;是一套利用计算机信息网络技术&#xff0c;实现对引用、注释和参考图书的自动化处理和规范化管理&#xff0c;服务于教师&#xff0c;学生及各类科研人员的集成…

【C语言进阶考试】你是否真正学懂了C语言

目录 前言 &#x1f392;选择题【全面深度剖析】 &#x1f4d7;考点一&#xff1a;无符号数unsigned的理解与应用 &#x1f4d5;考点二&#xff1a;字符ASCII计算与转换的理解和应用 &#x1f4d9;考点三&#xff1a;对位操作符的理解与应用 &#x1f4d8;考点四&#xf…

docker mysql 主从配置

准备&#xff1a;一台装有docker的虚拟机或者服务器 拉取mysql镜像&#xff1a; docker pull mysql:5.6 启动两个mysql容器 master docker run -p 1006:3306 --name mysql_master -v F:/mysql/mysql_master/conf:/etc/mysql -v F:/mysql/mysql_master/logs:/logs -v F:/mys…

【1024 | 程序员节】浅谈前端开发中常用的设计模式——适配器模式、工厂模式、单例模式等

前言 博主主页&#x1f449;&#x1f3fb;蜡笔雏田学代码 专栏链接&#x1f449;&#x1f3fb;【前端面试专栏】 今天学习前端面试题相关的知识&#xff01; 感兴趣的小伙伴一起来看看吧~&#x1f91e; 文章目录设计模式设计模式分类工厂模式什么是工厂模式工厂模式好处单例模式…

I2C知识大全系列三 —— I2C驱动之单片机中的I2C

两种方式 单片机中的I2C驱动有两种方式。一种方式是用专用硬件I2C控制器实现&#xff0c;这种方式简单易行&#xff0c;品质也容易控制&#xff0c;只是会增加硬件成本方面的压力。另一种方式是用纯软件方式实现&#xff0c;这种方式几乎无硬件成本方面的考虑。 主要对比&…

网页图片采集-网页图片采集软件免费

一款免费的网页图片采集软件可以采集网页上的各种图片&#xff0c;每个人都可以采集到各种高清图源。支持任意格式的图片采集&#xff0c;只需要导入链接即可批量采集图片。 还有更多的采集方式&#xff1a;输入关键词全网图片采集/任意网站所有图片采集&#xff01;不仅可以采…

【C++】STL——vector(万字详解)

&#x1f387;C学习历程&#xff1a;入门 博客主页&#xff1a;一起去看日落吗持续分享博主的C学习历程博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 也许你现在做的事情&#xff0c;暂时看不到成果&#xff0c;但不要忘记&…

记首次参加网络安全比赛(初赛-知识竞赛,决赛-CTF夺旗赛-解题模式)

网络安全相关的方向很多&#xff0c;几乎IT相关的安全内容都可以涵盖在内。笔者本身的知识体系更偏向于编程语言和Web应用&#xff0c;本次参赛可谓极具挑战&#xff0c;但是就是喜欢这种感觉&#xff1a;&#xff09; 赛程安排 9月16日接到通知 9月26日初赛 10月15日决赛 …

计算机网络习题答案

1、校园网属于&#xff08;局域网LAN &#xff09; 2、在下列传输介质中&#xff0c;(光缆 )传输介质的抗电磁干扰性最好。 3、光纤上采用的多路复用技术为&#xff08;WDM&#xff09; 4、计算机网络的交换方式不包括 无线交换 5、网络体系结构模型OSI模型和TCP/IP模型…

区块链实训教程(6)--开发、编译、部署、调用HelloWorld合约

文章目录1. 任务背景2. 任务目标3. 相关知识点4. 任务实操4.1 新建合约文件4.2 编写合约代码4.3 保存、编译、部署合约4.4 调用合约5. 任务总结1. 任务背景 FISCO BCOS运用智能合约进行归纳资产管理、规则定义和价值交换等操作&#xff0c;所以我们需要学习如何使用智能合约。…

aws ec2 配置jenkins和gitlab

环境搭建 下载jenkins的war包&#xff0c;启动jenkisn nohup java -jar jenkins.war --httpPort8091 > jenkins.log 2>&1 &docker安装gitlab 默认情况下&#xff0c;Omnibus GitLab 会自动为初始管理员用户账号 (root) 生成密码&#xff0c;并将其存储到 /etc…

HarmonyOS系统中内核实现温湿度采集方法

大家好&#xff0c;今天主要来聊一聊&#xff0c;如何使用鸿蒙系统中的温湿度传感器方法。 第一&#xff1a;温湿度传感器基本原理 大部分的传感器是在环境温度变化后会产生一个相应的延伸&#xff0c;因此传感器可以以不同的方式对这种反应进行信号转换。常见的大部分是电阻…

gitlab cicd 5分钟快速入门搭建私人代码仓库

gitlab 是企业级私有服务器 本文章采用docker搭建gitlab 如有不懂可微信我号yizheng369 环境准备 购买阿里云服务器&#xff0c;或者其他服务器 注意&#xff1a;本文章是用阿里云的centos 7.6作为服务器 搭建步骤 1.设置环境变量 export GITLAB_HOME/srv/gitlab2.编写dock…

今天面了个阿里拿27k出来的小哥,让我见识到了什么是天花板

2022年堪称大学生就业最难的一年&#xff0c;应届毕业生人数是1076万。失业率超50%&#xff01; 但是我观察到一个数据&#xff0c;那就是已经就业的毕业生中&#xff0c;计算机通信等行业最受毕业生欢迎&#xff01; 计算机IT行业薪资高&#xff0c;平均薪资是文科其他岗位的3…