数据结构——常见的十种排序算法

一、常见的十种排序算法:
冒泡排序、选择排序、插入排序、归并排序、快速排序、希尔排序、堆排序、计数排序、桶排序、基数排序
1.【知识框架】
在这里插入图片描述

补充:
内部排序:整个排序过程完全在内存中进行。
外部排序:由于待排序记录数据量太大,内存无法容纳全部数据,需要借助外部存储。

二、排序方法

插入排序
•直接插入排序
1.算法思想
从待排序的第二个元素开始,向下扫描列表,比较这个目标值target与arr[i-1]、arr[i-2]的大小,依次类推。如果target的值小于或等于每一个元素值,那么每个元素都会向右滑动一个位置,一旦确定了正确位置j,目标值target(即原始的arr[i])就会被复制到这个位置。(例如:整理桥牌时,我们会将每一张牌插入到一个已经有序的序列的适当位置。为了给要插入的元素腾出空间,需要我们将已经有序的序列元素都向右移动一位)
2.算法实现

在这里插入图片描述

3.插入排序伪代码

 1 void InsertSort (ElemType A[], int n)2 {3    int i,j;4    for(i=2;i<=n;i++)5         if(A[i].key<A[i-1].key)6     {7         A[0]=A[i];8         for(j=i-1;A[0].key<A[j].key;--j)9                 A[j+i]=A[j];
10         A[j+i]=A[0];
11     }
12 }

4.稳定性

由于每次插入元素时总是从后往前先比较在移动,所以不会出现相同元素相对位置,发生变化的情况即直接插入排序是一个稳定的排序方法

5.时间复杂度:O(n²)

•希尔排序(缩小增量排序)

1.算法提出:
为解决插入排序每次只能将数据移动一位,在数组较大且基本无序的情况下性能出现的恶化所以引入其算法。
2.算法思想:
先取一个小于n的步长d1把表中全部记录分成d1个组,所有距离为d1的倍数的记录放在同一个组中,在各组中进行直接插入排序:然后取第二个步长d2<d1,重复上 述过程,直到所取到的d1=1,即所有记录已放在同一组中,再进行直接插入排序,由于此时已经具有较好的局部有序性,故可以很快得到最终结果。到目前为 止,尚未求得一个最好的增量序列,希尔提出的方法是d1=n/2,di+1=⌈di/2⌉ , 并且最后一个增量等于 1。
3.算法实现:
在这里插入图片描述

补充:操作原理时间复杂度与选取的增量序列有关且所取增量序列的函数介于O(N*logN)和O(n²)之间增量序列有很多种取法,但是使增量序列中的值没有除1之外的公因子,并且增量序列中最后一个值必须为1。

4.希尔排序伪代码

 1 void ShellSort (ElemType A[],int n){2 //对顺序表作希尔插入排序,基本算法和直接插入排序相比,做了以下修改:3 //1.前后记录位置的增量是dk,不是14 //2.r[0]只是暂时存储单元,不是哨兵,当j<=0时,插入位置已到5       for(dk=n/2;dk>=1,dk=dk/2)                                   //步长变化6            for(i=dk+1;i<=n;++i) 7                  if(A[i].key<A[i-dk].key){                        //需将A[i]插入有序增量子表8                      A[0]=A[i];                                                       9                      for(j=i-dk;j>0&&A[0].key<A[j].key;j-=dk) 
10                           A[j+dk]=A[j];                           //记录后移,查找插入位置
11                      A[j+dk]=A[0];                                //插入
12                }//if
13   }

5.稳定性

当相同关键字的记录被划分到不同的子表时,可能会改变它们之间的相对次序,因此,希尔排序是一种不稳定的排序方法。例如,表L=[3,2,2].经过一趟排序后,L=[2,2,3],最终排序序列也是L=[2,2,3],显然2与2的相对次序已经发生了变化。

6.时间复杂度:O(N*logN)

选择排序

•简单选择排序

1.算法思想

Step1:将待排序数组分为有序和无序两组(初始情况下有序组为空)。

Step2:从左向右扫描无序组,找出最小的元素,将其放置在无序组的第一个位置。至此有序组++,无序组–;

Step3:重复Step2,直至无序组只剩下一个元素。

2.算法实现

3.选择排序伪代码

 1 void ShellSort (ElemType A[],int n){2 //对表A作简单的选择排序,A[]从0开始放元素3       for(i=0;i<=n-1;i++){                                //一共进行n-1趟4           min=i;                                          //记录最小元素位置5               for(j=i+1;j<n;j++)                          //在A[i...n-1]中选择最小的元素                                    6                      if(A[j]<A[min])7                            min=j;                         //更新最小元素位置8 if(min!=i)  swap(A[i],A[min]);                            //在第n个元素交换9                         
10                }
11 }

4.稳定性

选择排序的时间复杂度为O(n²),由于每次选择仅考虑某一位置上的数据情况,可能会破坏之前数据的相对位置,因此它是一种不稳定的排序方法。 例如:序列 [9,9,1]第一次就将第一个[9]与[1]交换,导致第一个9挪动到第二个9后面。

5.时间复杂度: O(n²)

补充:简单选择排序的比较次数与序列的初始排序无关。假设待排序的序列有 n个元素,选择排序的赋值操作介于0和3(n - 1次之间; 则比较次数永远都是n(n-1)/2; 而移动次数(即:交换操作)与序列的初始排序有关,介于 0 和 (n - 1) 次之间。当序列正序时,移动次数最少,为 0。当序列反序时,移动次数最多,为n - 1 次;逆序交换n/2次。选择排序的移动次数比冒泡排序少多了,由于交换所需CPU时间比 比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快。

•堆排序

1.引入概念
堆是一棵顺序存储的完全二叉树。其中每个结点的关键字都不大于其孩子结点的关键字,这样的堆称为小根堆。
其中每个结点的关键字都不小于其孩子结点的关键字,这样的堆称为大根堆。
举例来说,对于n个元素的序列{R0, R1, … , Rn}当且仅当满足下列关系之一时,称之为堆:

2.算法思想
堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。
如图:

3.算法实现(大顶堆)
注:若n为数组的个数,那么就从2/n开始,依次循环。
4.堆排序伪代码
下面是建立大根堆的算法:

 1    void BuildMaxHeap (ElemType A[], int len) {2           for(int i=len/2;i>0;i--)  //从i=[n/2]~1,反复调整堆3               AdjustDown(A, i, len) ;4 5    }6     void AdjustDown (ElemType A[], int k, int len) {7                  //函数AdjustDown将元素k向下进行调整8             A[0]=A[k] ;                         //A[O]暂存9             for (i=2*k;i<=len;i*=2){      //沿 key较大的子结点向下筛选
10                   if (i<len&&A[i] <A[i+1])
11                         i++;
12                   if(A[0]>=A[i]) break;       // 筛选结束
13                   else{
14                         A[k]=A[i];                //将A[i]调整到双亲结点上
15                         k=i ;                        //修改k值,以便继续向下筛选
16             }
17     }//for
18     A[k]=A[0];                                   //被筛选结点的值放入最终位置
19    }

下面是堆排序算法:

1                   void HeapSort (ElemType A[],int len) {
2                        BuildMaxHeap (A,len) ;          //初始建堆
3                        for(i=len;i>1;i--){              //n-1 趟的交换和建堆过程
4                        Swap (A[i],A[1]) ;                / /输出堆顶元素(和堆底元素交换)
5                        AdjustDown (A, 1, i-1) ;}     //整理,把剩余的i-1个元素整理成堆
6                 }//for
7            }

下面是向上调整堆的算法:

 1                void AdjustUp (ElemType A[], int k) {2                 //参数k为向上调整的结点,也为堆的元素个数3                    A[0]=A[k] ;4                    int i=k/2;  //若结点值大于双亲结点, 则将双亲结点向下调,并继续向上比较 5                    while (i>0&&A[i]<A[0]) {           //循环跳出条件6                           A[k]=A[i];                    //双亲结点下调 7                           k=i;8                           i=k/2;                           //继续向上比较9             }//while
10             A[k]=A[0] ;                                  //复制到最终位置
11        }

5.稳定性
堆排序是一种不稳定的排序方法。因为在堆的调整过程中,关键字进行比较和交换所走的是该结点到叶子结点的一条路径,因此对于相同的关键字就可能出现排在后面的关键字被交换到前面来的。
6.时间复杂度:O(N*logN)。

交换排序

•冒泡排序

1.算法思想

冒泡排序是一种交换排序,它的实现原理是:两两比较相邻的记录值,如果反序则交换,直到没有反序的记录为准。对数组中的各数据,依次比较相邻的两元素的大小。如果前面的数据大于后面的数据,就交换这两个数据。经过第一轮的多次比较排序后,变可把最小的数据排好。再用同样的方法把剩下的数据逐个进行比较,最后便可按照从小到大的顺序排好数组各数据的顺序。

2.算法实现

  1. 冒泡排序伪代码
 1 void BubbleSort (ElemType A[],int n){2 //用冒泡排序将序列A中的元素按从小到大排列3          for(i=0;i<n-1;i++){4               flag=false;                           //标示本趟冒泡是否发生交换标志5               for(j=n-1;j>i;j--)               //一趟冒泡过程6                    if(A[j-i].key>A[j].key){     //若为逆序7                          swap(A[j-1],A[j]);       //交换8                          flag=true;9                    }
10              if(flag==false)
11                   return;                            //本趟遍历没有发生交换,说明已经有序
12          }
13 }

4.稳定性

冒泡排序是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。相同元素的前后顺序并没有改变,冒泡排序是一种稳定排序算法。

5.时间复杂度: O(n²)

补充:若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数C和记录移动次数M均达到最小值:Cmin = N - 1, Mmin = 0。所以,冒泡排序最好时间复杂度为O(N)。若初始文件是反序的,需要进行 N -1 趟排序。每趟排序要进行 N - i 次关键字的比较(1 ≤ i ≤ N - 1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:Cmax = N(N-1)/2 = O(N^2) Mmax = 3N(N-1)/2 = O(N2)冒泡排序的最坏时间复杂度为O(N2)。因此,冒泡排序的平均时间复杂度为O(N^2)。当数据越接近正序时,冒泡排序性能越好。

•快速排序

1.基本概念

快速排序为应用最多的排序算法,因为快速二字而闻名。快速排序和归并排序一样,采用的都是分治思想。快速排序可以分为:单路快速排序,双路快速排序,三路快速排序,他们区别在于选取几个指针来对数组进行遍历 。

1.算法思想

快速排序是对冒泡排序的一种改进。其基本思想是基于分治法的:在待排序表L[`1…n]中任取一个元素 pivot作为基准,通过一趟排序表将待排序表划分为独立的两部分
L[1…k-1]和L[k+1…n],使得L[1…k-1]中所有元素小子pivot, L[k+1…n]中所有元素大于或等于pivot,则pivot放在了其最终位置L(k)上,这个过程称作一趟快速排序。 而后分别递归地对两个子表重复上述过程,直至每部分内只有一个元素或空为止,即所有元素放在了其最终位置上。

2.算法实现

注:后找小前找大

  1. 快速排序伪代码

首先假设划分算法已知,记为Partition(),返回的是上述中的k,注意到L(k)已经在最终的位置,所以可以先对表进行划分,而后对两个表调用同样的排序操作。因此可以递归地调用快速排序算法进行排序,具体的程序结构如下:

1 void QuickSort (ElemType A[],int low,int high){
2
3 if (low<high) { //递归跳出的条件
4 //Partition()就是划分操作,将表low-high划分为满足上述条件的两个子表
5 int pivotpos-=Partition(A, low,high); //划分//依次对两个子表进行递归排序
6 QuickSort MB (A, low,pivotpos-1);
7 QuickSort (A, pivotpos+1,high) ;
8 }
9 }

从上面的代码也 不难看出快速排序算法的关键在于划分操作,同时快速排序算法的性能也主据要取决于划分操作的好坏。假设每次总是以当前表中第一个元素作为枢轴值 (基准)对表进行划分,则必须将表中比枢轴值大的元素向右移动,比枢轴值小的元素向左移动,使得一趟Partition()操作之后,表中的元素被枢轴值一分为二。
4.稳定性
快速排序有两个方向,左边的i下标一直往右走,当a[i] <= a[center_index],其中center_index是中枢元素的数f组下标,一般取为数组第0个元素。而右边的j下标一直往左走,当a[j] > a[center_index]。如果i和j都走不动了,i <= j, 交换a[i]和a[j],重复上面的过程,直到i>j。 交换a[j]和a[center_index],完成一趟快速排序。在中枢元素和a[j]交换的时候,很有可能把前面的元素的稳定性打乱,比如序列为 5 3 3 4 3 8 9 10 11, 现在中枢元素5和3(第5个元素,下标从1开始计)交换就会把元素3的稳定性打乱,所以快速排序是一个不稳定的排序算法,不稳定发生在中枢元素和a[j] 交换的时刻。
5.时间平均复杂度: O(nlog2n)。

基数排序(桶排序)
1.基本概念
基数排序(Radix Sort)属于分配式排序,又称"桶子法"(Bucket Sort或Bin Sort),将要排序的元素分配到某些"桶"中,以达到排序的作用。基数排序属于稳定的排序,其时间复杂度为nlog®m (其中r为的采取的基数,m为堆数),基数排序的效率有时候高于其它比较性排序。

2.算法思想

  1. 根据输入建立适当个数的桶,每个桶可以存放某个范围内的元素;
    2.将落在特定范围内的所有元素放入对应的桶中;
    3.对每个非空的桶中元素进行排序,可以选择通用的排序方法,比如插入、快排;
    4.按照划分的范围顺序,将桶中的元素依次取出。排序完成。
  2. 算法实现
    数组: int arr[] = {278,109,63,930,589,184,505,269,8,83};

个位分配,个位收集,先进后出。

十位分配,十位收集,先进后出。

百位分配,百位收集,先进后出。

4.稳定性
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优 先级排序,最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以其是稳定的排序算法。

5.时间平均复杂度:O(d(n+r))

归并排序(二路归并排序)

1.基本概念
归并排序是通过“归并”操作完成排序的,将两个或者多个有序子表归并成一个子表。归并排序是“分治法”的一个非常典型的应用,同事它也是递归算法的一个好的实例。它将问题分成一些小的问题然后递归求解,而治就是把分阶段的答案拼起来。
2.算法思想
将一个大小为 n 的数组排序。归并排序算法的排序步骤是:

1.将所有的数字放入一个无序的堆。
2.将堆分成两部分,现在你有两个无序的堆。
3.持续将无序的堆拆分,直到无法再拆分为止,你将得到 n 个堆,每一个堆中有一个数字。
4.现在开始将这些堆按照一定顺序按对合并。每一次合并过程中,将堆中的数字放入有序的队列。这一点很容易实现,因为每一个独立的堆中的内容都是有序的。
3.算法实现

数组: int arr[] = {3,6,1,7,9,4,5,8,2}
二路归并排序的过程如图所示:

4.稳定性
归并排序的空间复杂度O(n)。另外,归并排序中归并的算法并不会将相同关键字的元素改变相对次序,所以归并排序是稳定的。
5.时间平均复杂度:O(nlog2n)。

后续未完…

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

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

相关文章

vued中图片路径与主机路径相关联,例如img:‘http://127.0.0.1:8000/media/data/els.jpg‘

1.在Django项目的settings.py文件中&#xff0c;确保已指定正确的MEDIA_URL和MEDIA_ROOT。MEDIA_URL定义了图片的URL前缀&#xff0c;MEDIA_ROOT定义了本地文件系统中存储图片的路径。 2.在 Django 项目的主 urls.py 文件中&#xff0c;确保包含了适当的 URL 配置&#xff0c;以…

mfoc-hardnested在visual studio2022编译

1、点击mfoc-hardnested.sln 2、没有clang LLVM (clang-cl) (未安装) 打开installer 点击修改: 单个组件中搜索clang &#xff0c;安装即可 3、编译 4、main函数 5、mfoc-hardnested.exe使用

关于webWorker未解问题

今天尝试学习webworker,尝试在vue3项目里面使用 使用的就是常规方法,使用worker-loader,加上在vue.config.js内部添加配置 使用完发现问题 如图所见,该worker仅仅配置点击后传输字符串"1",并在worker内部打印,发现打印不出来 但是仅仅只是将引入的文件换个名字 …

基于springboot实现汽车租赁管理系统项目演示【项目源码+论文说明】分享

基于springboot实现汽车租赁管理系统项目演示 摘要 随着社会的发展&#xff0c;计算机的优势和普及使得汽车租赁系统的开发成为必需。汽车租赁系统主要是借助计算机&#xff0c;通过对汽车租赁信息等信息进行管理。减少管理员的工作&#xff0c;同时也方便广大用户对个人所需汽…

用OpenCV(Python)获取图像的SIFT特征

import cv2 as cv import numpy as np import matplotlib.pyplot as plt imgcv.imread("../Lena.png") img_graycv.cvtColor(img,cv.COLOR_BGR2GRAY)#创建一个SIFI对象 siftcv.SIFT_create()#使用SIFT对象在灰度图像img_gray中检测关键点&#xff0c;结果存储在变量k…

解读非托管流动性协议Hover: 差异化、层次化的全新借贷体系

“Hover 是 DeFi 借贷赛道的另辟蹊径者&#xff0c;除了在自身机制&#xff08;借贷模型、治理体系&#xff09;上进行创新获得内生动力外&#xff0c;背靠日渐繁荣的 Kava、Cosmos 生态进一步获得外生动力&#xff0c;发展潜力俱佳” 与 DEX 类似&#xff0c;借贷也是 DeFi 世…

对一门不是非常熟悉的语言是怎么面试的

公司是一个基础通讯类的公司&#xff0c;需要的职位是一个高级系统和软件工程师。 职位要求&#xff0c;是一个完全不怎么大众的语言&#xff1a;Elixir。 没听过&#xff0c;这就对了&#xff0c;这是一个函数式的语言&#xff0c;可以认为是 Erlang 的升级版本&#xff0c;…

Postgresql源码(115)LLVM JIT运行逻辑分析(上)

1 JIT入口开关 总入口&#xff1a;jit_enabled打开 且 生成计划成本超过jit_above_cost启动JIT。 计划成本超过jit_optimize_above_cost&#xff0c;执行PGJIT_OPT3使用O3对IR进行优化。计划成本超过jit_inline_above_cost&#xff0c;执行PGJIT_INLINE。jit_expressions开关如…

Linux网络监控工具 - iftop

iftop 是一个基于 libpcap 库的网络流量监控工具。它通过监听指定网络接口上的数据包&#xff0c;并分析这些数据包的源地址、目标地址、源端口、目标端口、协议等信息&#xff0c;从而实时显示网络流量的相关统计信息。 安装 在大多数Linux发行版中&#xff0c;您可以使用包管…

【排序算法】冒泡排序

文章目录 一&#xff1a;排序算法1.1 介绍1.2 分类 二&#xff1a;冒泡排序2.1 基本介绍2.2 图解冒泡排序算法2.3 代码实现 三&#xff1a;算法性能分析3.1 时间复杂度3.2 空间复杂度 一&#xff1a;排序算法 1.1 介绍 排序也称排序算法(Sort Algorithm)&#xff0c;排序是将…

upload-labs靶场通关

文章目录 Pass-01 前端检测&#xff08;JS检测&#xff09;1.1 原理分析1.2 实验 Pass-02 后端检测&#xff08;MIME检测&#xff09;2.1 原理分析2.2 实验 Pass-03 后端检测&#xff08;黑名单绕过&#xff0c;特殊后缀名&#xff09;3.1 原理分析3.2 实验 Pass-04 后端检测&a…

【力扣-每日一题】2034. 股票价格波动

class StockPrice { private:unordered_map<int,int> mp; //存储日期及其对应的价格multiset<int> st; //存储所有价格int last_day; //最新一天 public:StockPrice() {this->last_day0;}void update(int timestamp, int price) {if(mp.find(timestamp)!mp…

leetCode 1143.最长公共子序列 动态规划 + 滚动数组

1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串…

大数据—数据透析表常见使用(手把手详解)

我的个人主页&#xff1a;☆光之梦☆_C语言基础语法&#xff08;超详细&#xff09;,【java入门】语法总结-CSDN博客 创作不易&#xff0c;如果能帮到你就好 注&#xff1a;你的 &#x1f44d;点赞 ⭐收藏 &#x1f4dd;评论 是对博主最大的支持与鼓励喔 目录 一、创建数据透…

【微服务】七. http客户端Feign

7.1 基于Feign远程调用 RestTimeplate方式调用存在的问题 先来看以前利用RestTemplate发起远程调用的代码&#xff1a; String url "http://userservice/user"order.getUserId(); User user restTemplate.getForObject(url,User.class);存在下面的问题&#xf…

Vue Router的进阶

进阶 导航守卫 官方文档上面描述的会比较深奥&#xff0c;而守卫类型也比较多&#xff0c;其中包含了全局前置守卫、全局解析守卫、全局后置钩子、路由独享守卫、组件内守卫。每一种守卫的作用和用法都不相同。这会使得大家去学习的时候觉得比较困难&#xff0c;这边主要介绍…

CentOS Stream9 安装远程桌面服务 Xrdp

1. 安装 XRDP 若服务器本身没有桌面则首先需要安装本地桌面&#xff1a; yum -y groups install "GNOME Desktop" startx配置源&#xff1a; dnf install epel-release安装 xrdp dnf install xrdp 2. 配置 Xrdp Xrdp 配置文件位于 /etc/xrdp 目录中。对于常规 X…

HTTP长连接实现原理

1. HTTP长连接和短连接的定义 HTTP长连接 浏览器向服务器进行一次HTTP会话访问后&#xff0c;并不会直接关闭这个连接&#xff0c;而是会默认保持一段时间&#xff0c;那么下一次浏览器继续访问的时候就会再次利用到这个连接。在HTTP/1.1版本中&#xff0c;默认的连接都是长连…

计算机算法分析与设计(8)---图像压缩动态规划算法(含C++)代码

文章目录 一、知识概述1.1 问题描述1.2 算法思想1.3 算法设计1.4 例题分析 二、代码 一、知识概述 1.1 问题描述 1. 一幅图像的由很多个像素点构成&#xff0c;像素点越多分辨率越高&#xff0c;像素的灰度值范围为0~255&#xff0c;也就是需要8bit来存储一个像素的灰度值信息…

New Journal of Physics:不同机器学习力场特征的准确性测试

文章信息 作者&#xff1a;Ting Han1, Jie Li1, Liping Liu2, Fengyu Li1, * and Lin-Wang Wang2, * 通信单位&#xff1a;内蒙古大学物理科学与技术学院、中国科学院半导体研究所 DOI&#xff1a;10.1088/1367-2630/acf2bb 研究背景 近年来&#xff0c;基于DFT数据的机器学…