算法基础:常用的排序算法知识笔记

1、算法外排序分类

 

              

2、冒泡排序

冒泡排序(Bubble Sort)属于交换排序,它的原理是:循环两两比较相邻的记录,如果反序则交换,直到没有反序的记录为止。

实现算法:

/**

 * 冒泡排序优化后的算法

 * 设置一个标记来标志一趟比较是否发生交换

 * 如果没有发生交换,则数组已经有序

 */

void bubbleSort(SqList *L){

    int i,j;    

    int flag = true;  // flag 用来作为标记

    for (i = 1; i < L->length && flag; i++) { 

  // 若flag为true 则说明数据交换过,否则没交换过(数组已经有序) 则停止循环

        flag = false;

        for (j = L->length - 1; j >= i; j--) {

            if (L->r[j] > L->r[j+1]) {

                swap(L, j, j+1);

                flag = true;  // 如果有数据交换 flag为true

            }

        }

    }

}

3、简单选择排序

简单选择排序法(Simple Selection Sort)是通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换。

原理是:每一次从无序数据组的数据元素中选出最小(或最大)的一个元素,存放在无序数组的开始位置,随着无序数组元素减少,有序组元素增加,直到全部待排序的数据元素完全排完。

/**

 * 简单选择排序算法

 */

void selectSort(SqList *L){

    int i, j, min;

    for (i = 1; i < L->length; i++) {

        min = i;    // 将当前下标定义为最小值下标

        for (j = i + 1; j <= L->length; j++) {

            if (L->r[min] > L->r[j])

                min = j;

        }

        

        if (i != min)  // 若min不等于 i 说明找到最小值, 交换

            swap(L, i, min);

    }

}

4、直接插入排序

直接插入排序(Straight Insertion Sort)的是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录增1的有序表。

原理:将一个记录插入到一个已经排序好的表中,得到一个记录增加1的有序表。并且它把当前元素大的记录都往后移动,用以腾出“自己”该插入的位置。当n-1趟插入完成后就是需要的有序序列。

/**

 *直接插入排序算法

 */

void InsertSort(SqList *L){

    int i, j;

    for (i = 2; i < L->length; i++) {        

        if (L->r[i] < L->r[i-1]) { // 需要将 L->r[i] 插入有序子表            

            L->r[0] = L->r[i]; // 设置哨兵

            for (j = i-1; L->r[j] > L->r[0]; j++)

                L->r[j+1] = L->r[i]; // 记录后移            

            L->r[j+1] = L->r[0]; // 插入到正确位置

        }

    }

}

5、希尔排序

希尔排序是对直接插入排序的改进排序算法。希尔排序又叫缩小增量排序。

原理:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。属于不稳定排序算法。

/**

 *  希尔排序算法

 */

void shellSort(SqList *L){    

    int i,j;

    

    int increment = L->length;  // 增量初始值等于排序记录

    

    do {

        increment = increment /3 +1;  // 增量序列

        

        for (i = increment + 1; i < L->length; i++) {

            

            if (L->r[i] < L->r[i-increment]) {  // 需要将 L->r[i] 插入有序增量子表

                

                L->r[0] = L->r[i];  // 用哨兵暂时存放 L->r[i]

                

                for (j = i - increment; i >0 && L->r[0] < L->r[j]; j -= increment)

                    L->r[j+increment] = L->r[j];  // 记录后移, 查找插入位置

                    

                L->r[j+increment] = L->r[0];  // 插入

            }

        }

    } while (increment > 1);  // 增量不大于 1 时停止循环

}

6、堆排序

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

算法过程描述

1、将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;

2、将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];

3、由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

 

堆排序是一种不稳定的排序方法。

 

/**

 * 已知 L->r[s..m] 中记录的关键字除L->r[s]之外均满足堆的定义

 * 该函数调整L->r[s] 的关键字,使L->r[s..m]成为一个大顶堆

 */

void HeadAdjust(SqList *L, int s, int m){

    int temp, j;

    temp = L->r[s];    

    for (j = 2 *s; j <= m; j *= 2) {  // 沿关键字较大的孩子结点向下筛选  这里循环的条件j从 2*s 开始是因为利用了二叉树的性质5:由于这颗是完全二叉树,当前节点序号是 s ,其左孩子的序号一定是 2s, 右孩子的序号一定是 2s+1,它们的孩子当然也是以 2 的位数序号增加,因此 j 变量才这样循环。        

        if (j < m && L->r[j] < L->r[j+1])  // 1. j < m 说明它不是最后一个节点  2. L->r[j] < L->r[j+1]) 说明左孩子小于右孩子

            j++;  // j 为关键字中较大的记录的下标        

        if (temp >= L->r[j])

            break;  // rc应插入在位置s上        

        L->r[s] = L->r[j];

        s = j;

    }    

    L->r[s] = temp;  // 插入

}

/**

 * 对顺序表L进行堆排序

 */

void HeapSort(SqList *L){

    int i;    

    for (i = L->length / 2; i>0; i--)   // 把L中的r构建成一个大顶堆

        HeadAdjust(L, i, L->length);    

    for (i = L->length; i > 1; i--) {

        swap(L, 1, i);  // 将堆顶记录和当前未经排序子序列的最后一个记录交换

        HeadAdjust(L, 1, i-1);  // 将L->r[1..i-1]重新调整为大顶堆

    }

}

7、归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

实现原理(递归实现):

1、将序列平均分成两部分

2、分别对这两部分用递归来归并

3、将这两部分归并到一起

算法示例

#p.归并排序(递归实现)

/**

 * 将有序的 SR[i..m] 和 SR[m+1..n]归并为有序的 TR[i..n]

 */

void Merge(int SR[], int TR[], int i, int m, int n){

    

    int j, k, l;

    

    for (j = m+1, k = i; i <= m && j <= n; k++) { // 将SR中记录有小到大归并入TR

        

        if (SR[i] < SR[j])

            TR[k] = SR[i++];

        else

            TR[k] = SR[j++];

    }

    

    if (i <= m) {

        for (l=0; l <= m-i; l++)

            TR[k+l] = SR[i+l];  // 将剩余的SR[i..m]复制到TR

    }

    

    if (j <= n) {

        for (l=0; l <= n-j; l++)

            TR[k+l] = SR[j+l]; // 将剩余的SR[j..n]复制到TR

    }

}

 

/**

 *将SR[s..t]归并排序为TR1[s..t]

 */

void MSort(int SR[], int TR1[], int s, int t){

 

    int m;

    int TR2[MAXSIZE+1];

    

    if (s == t) {

        TR1[s] = SR[s];

    }else{

        m = (s+t)/2; // 将SR[s..t]平分为SR[s..m]和SR[m+1..t]

        MSort(SR, TR2, s, m);   // 递归将SR[s..m]归并为有序的TR2[s..m]

        MSort(SR, TR2, m+1, t); // 递归将SR[m+1..t]归并为有序的TR2[m+1..t]

        Merge(TR2, TR1, s, m, t); // 将TR2[s..m]和TR2[m+1..t]归并到TR1[s..t]

    }

}

 

/**

 *  对顺序表L作归并排序

 */

void MergeSort(SqList *L){

    MSort(L->r, L->r, 1, L->length);

}

归并排序是一种比较占内存,但是效率高且稳定的算法。

 

 

8、快速排序

实现原理:

选取一个关键字,放到一个位置,使得它的左边的值都比它小,右边的值都比它大,这个关键字叫做枢轴(pivot)

然后分别对左边和右边进行排序。

#p快速排序

/**

 * 交换顺序表 L 中子表的记录,使轴记录到位,并返回其所在位置

 * 此时在它之前的记录均不大于它,在它之后的记录均不小于它

 */

int partition(SqList * L, int low, int high){    

    int pivotkey;

    pivotkey = L->r[low];  // 用子表的第一个记录作为枢轴记录    

    while (low < high) {  // 从表的两端交替地向中间扫描

        while (low < high && L->r[high] >= pivotkey)

            high --;

        swap(L, low, high);  // 将比枢轴小的记录交换到低端        

        while (low < high && L->r[low] <= pivotkey)

            high++;

        swap(L, low, high);  // 将比枢轴大的记录交换到高端

    }    

    return low;  // 返回枢轴所在位置

}

 

/**

 * 对顺序表 L 中的子序列 L->r[low..high] 作快速排序

 */

void QSort(SqList *L, int low, int high){    

    int pivot;

    if (low < high) {

        pivot = Partition(L, low, high);  // 将L->r[low..high]一分为二,算出枢轴值pivot

        QSort(L, low, pivot-1);  // 对 低子表递归排序

        QSort(L, pivot+1, high); // 对 高子表递归排序

    }

}

/**

 * 对顺序表 L 作快速排序

 */

void QuickSort(SqList *L){

    QSort(L, 1, L->length);

}

 

 

9、排序算法比较

              

10、排序算法总结

10.1 内部排序

1、排序的记录数量较少是,可以考虑插入排序和简短选择排序。如果记录本身信息量较大时,建议选用选择排序。

2、如果待排序记录按关键字基本有序,适合采用冒泡排序或直接插入排序

3、若 排序记录较大,可以选择快速排序、堆排序或归并排序。目前快速排序被认为最好的排序方法。

10.2 外部排序

外部排序就是针对大型文件的排序。常用的外部排序方法是归并排序。

 

IT技术分享社区

个人博客网站:https://programmerblog.xyz

文章推荐程序员效率:画流程图常用的工具程序员效率:整理常用的在线笔记软件远程办公:常用的远程协助软件,你都知道吗?51单片机程序下载、ISP及串口基础知识硬件:断路器、接触器、继电器基础知识

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

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

相关文章

302状态码_http状态码是什么?301 302 404的SEO应用场景

什么是HTTP状态码&#xff1f;简单的讲&#xff0c;就是用以表示网页服务器HTTP响应状态的3位数字代码。其中1xx表示临时响应&#xff0c;2xx表示成功处理了请求&#xff0c;3xx代表重定向&#xff0c;4xx表示请求错误&#xff0c;而5xx表示服务器错误。除了网页正常返回200之外…

算法基础:常用的查找算法知识笔记

1、查找表和查找效率的概念查找表是指由同一类型的数据元素构成的集合。分为静态查找表和动态查找表。1.1 静态查找表1、查询某个特定元素是否在查找表的集合当中2、查询某个特定元素的各种属性1.2 动态查找表1、在查找表中插入一个数据元素2、在查找表中删除一个元素1.3 关键字…

注解参数怎么使用变量_硅橡胶胶水有哪些特点?使用参数表现的怎么样?如何储存?...

作为单组分产品&#xff0c;硅橡胶胶水的使用方法简单又灵活。直接涂抹在粘接基面上&#xff0c;固化之后即可抵抗外界的压力与冲击。别看它的规格不是很打&#xff0c;却可以顺顺利利完成粘接&#xff0c;形成保护膜。硅橡胶胶水有哪些特点?没有固化之前&#xff0c;是半透明…

Java中return的两种用法

一、return语句总是用在方法中&#xff0c;有两个作用。 一个是返回方法指定类型的值&#xff08;这个值总是确定的&#xff09;。 一个是结束方法的执行&#xff08;仅仅一个return语句&#xff09;。 一般的就百是用在有反回值的方法中&#xff0c;用来返回方度法指定问类…

算法基础:递归算法知识笔记

1、递归算法定义递归算法是将重复问题分解为同类的子问题而解决问题的方法&#xff0c;其核心思想是分治策略。简单来说就是自己调用自己。直到达到退出递归的条件&#xff0c;则完成递归。2、递归的步骤1、找整个递归的终止条件&#xff1a;递归应该在什么时候结束&#xff1f…

ttl继承逻辑门的逻辑功能与参数测试 实验总结_LMS电声测试仪,LMS-V测试系统,精声电声...

LMS-V测试系统LMS扬声器测试仪从推出到现在25年的时间&#xff0c;在全世界被很多扬声器开发与制造厂家广泛应用研发与生产质量控制&#xff0c;传统的LMS扬声器测试仪采用ISA卡的形式提供&#xff0c;所以面临着越来越多的零件过时&#xff0c;所以为了彻底解决这些问题&#…

java中break标记的使用

笔试题目&#xff1a;break目前位于内层的for循环&#xff0c;如何才能让break作用于外层 的for循环。可以标记解决 标记的命名只要符合标识符的命名规则即可。 Test public void test2(){aaa:for(int j 0 ; j<3 ; j){ // j0 外层for循环for(int i 0 ; i< 2 ; i){ //…

电脑基础知识入门:键盘上的英文,意思和功能汇总!

电脑键盘是把文字信息的控制信息输入电脑的通道&#xff0c;从英文打字机的键盘演变而来的。它最早出现在电脑上的时候&#xff0c;还是一种叫做“电传打字机”的部件。那些陌生的键盘按键都有什么用途?很多孩子不知道键盘上功能键和字母数字键以外的键盘按键有什么用&#xf…

elementui el-dialog 离顶部的位置_驻马店建筑物避雷带的安装位置,本月报价

首页 > 新闻中心发布时间&#xff1a;2020-11-06 18:23:42 导读&#xff1a;科杰防雷为您提供驻马店建筑物避雷带的安装位置的相关知识与详情&#xff1a; 该系统在正常运行时&#xff0c;不管三相负荷平衡不平衡&#xff0c;在中性线N带电情况下&#xff0c;PE线不会带电。…

android 弹出框带标题栏,Android开发靠标题栏的弹框

一、效果图title_dialog.png二、思路首先它是一个弹框&#xff0c;只是弹框的布局做些处理&#xff0c;布局占满屏幕&#xff0c;只有需要白色的布局的背景设为白色。其他没设置背景颜色&#xff0c;自然用dialog的style的windowBackground三、案例关键代码dialog的xmlxmlns:ap…

算法基础:图的相关算法知识笔记

一、图的相关算法1、图的分类知识如下图&#xff1a;2、生成树概念对连通图进行遍历&#xff0c;过程中所经过的边和顶点的组合可看做是一棵普通树&#xff0c;通常称为生成树。连通图的生成树具有这样的特征&#xff1a;边的数量 顶点数 - 13、最小生成树在连通网的所有生成树…

java中break和continue的用法例子

break用于switch语句 1. break用于switch语句中&#xff0c;终止switch语句 下面先看 加上break,效果如下 我们可以看到&#xff0c;没有用过break关键字时&#xff0c;不会在判断下一个case的值&#xff0c;直接向后运行&#xff0c;直到遇到break&#xff0c;或者整体swit…

ftp 工具_ftp工具,ftp工具有哪些

对于ftp工具&#xff0c;你了解多少&#xff1f;其实一般人也接触不到这种软件。ftp工具主要是针对从事网站管理的工作人员比较有利的一款工具。可以帮助他们快速的解决工作中的问题。方便、简单、快捷又明了的解决问题。那ftp工具有哪些呢&#xff1f;接下来给大家推荐四款好用…

盘点世界十大软件外包公司排名是哪些公司

排名第一:IBMIBM,总部在纽约的阿蒙克。托马斯沃森19世纪80年代在美国成立,是全球最大的信息技术和商业解决方案公司,在全球拥有超过30万名员工,业务遍及160多个国家和地区。电脑上的制作非常出名,事实上,IBM在软件方面取得了巨大的成就,特别是在一些IBM服务器上使用的软件平台上…

判断不为空和不为空串的方法java

判断不为空和不为空串的方法 方法一:用StringUtils工具类 首先要引入依赖 <dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId> </dependency> if( StringUtils.isNotBlank(str3) && St…

android xml事件,安卓事件

1、自定义内部类2、匿名内部类3、当前activity去实现事件接口4、在布局文件xml中添加点击事件属性(使用频率非常高)补充&#xff1a;a、Android 在xml文件中 给某个控件声明 id 是: "/自定义名字" &#xff0c;获取是&#xff1a; "/自定义的名字" &#x…

Cocos2d-x v3.0物理系统 利用PhysicsEditor创建多边形

Cocos2d-x 3.0的新物理系统我就不必多说了&#xff0c;接触一段时间&#xff0c;感觉还是不错的。对于那些基本概念&#xff0c;网上的教程已经泛滥了&#xff0c;就不多说了&#xff0c;不过对于创建多边形物体的教程&#xff0c;还真不多&#xff0c;很多都是创建圆形和矩形&…

公众号开发 单独 给某个用户 推送消息_韩国5G用户6月底已达134万 较5月底增加近70%...

中关村在线消息&#xff1a;韩国三大运营商SK、KT和LG率先于去年12月开始向企业用户提供商用5G 服务&#xff0c;今年4月初推出面向个人消费者的5G民用服务。韩国作为全球首个推出5G 服务的国家&#xff0c;他们的5G用户数量在6月时已经突破100万大关。日前韩国公布6月底最新的…

程序语言的概念知识笔记

1、低级语言和高级语言 计算机指令程序&#xff1a;0、1 组成的机器指令序列。特点&#xff1a;效率低、可读性差、难以维护。 汇编指令&#xff1a;用常用的符号代替0、1 序列来 表示机器指令&#xff0c;例如用ADD表示加法。 高级语言&#xff1a;面向对象设计的各类应用的程…

java lambda 表达式中的双冒号和箭头的用法 ::

先构造一些数据,创建一个User类 java lambda 表达式中的双冒号的用法 &#xff1a;&#xff1a; 双冒号运算就是Java中的[方法引用],[方法引用]的格式是 类名::方法名 如下图所示 User是一个类, getAge是方法名,注意是方法名呀&#xff0c;后面没有括号()的。为什么不要括号…