八大排序算法总结

合集下载

排序算法总结

排序算法总结

排序算法总结排序算法是计算机科学中的一个重要主题,它是对一组数据进行排序的过程。

排序算法可以分为内部排序和外部排序两种类型。

内部排序是指所有数据都在内存中进行排序,而外部排序是指数据太大,无法全部存储在内存中,需要借助外部存储器进行排序。

常见的内部排序算法有冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序和基数排序等。

下面对这些算法进行总结。

1. 冒泡排序冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就交换它们的位置。

时间复杂度为O(n^2)。

2. 选择排序选择排序是一种简单直观的排序算法,它的基本思想是每次从未排序的数据中选择最小(或最大)的一个元素,存放到已排序的数据序列的末尾。

时间复杂度为O(n^2)。

3. 插入排序插入排序是一种简单直观的排序算法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增加1的有序表。

时间复杂度为O(n^2)。

4. 希尔排序希尔排序是一种基于插入排序的快速排序算法,它的基本思想是将待排序的数组按照一定的间隔分成若干个子序列,对每个子序列进行插入排序,然后逐步缩小间隔,直到间隔为1,最后对整个数组进行插入排序。

时间复杂度为O(nlogn)。

5. 归并排序归并排序是一种稳定的排序算法,它的基本思想是将待排序的数组分成若干个子序列,每个子序列都是有序的,然后再将子序列合并成一个有序的序列。

时间复杂度为O(nlogn)。

6. 快速排序快速排序是一种常用的排序算法,它的基本思想是通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

时间复杂度为O(nlogn)。

7. 堆排序堆排序是一种树形选择排序算法,它的基本思想是将待排序的数组构建成一个大根堆或小根堆,然后依次将堆顶元素与堆底元素交换,再重新调整堆,直到整个数组有序。

算法分析与设计八大排序

算法分析与设计八大排序

算法八大排序详解1.排序的基本概念:排序是各门语言中的核心,也是计算机数据处理中的核心运算,是我们学过的“数据结构与算法”课程的重点。

排序算法能够体现算法设计和算法分析的精神。

有效的排序算法在一些算法(例如搜索算法与合并算法)中是重要的,如此这些算法才能得到正确解答。

这篇博文主要包含了8大内部排序的算法复杂度,稳定性以及描述算法和可视化过程,花时间总结了很久,但是肯定仍有不足,希望各位大神能指点迷津。

小注:刚发现,可视化过程的图片是gif格式,但是传上去之后好像不动,不好意思。

请在点连接:可视化视图视觉直观感受7 种常用的排序算法(在最后的参考资料中也有)(1)排序算法的输出必须遵守下列两个原则:a)输出结果为递增串行(递增是针对所需的排序顺序而言);b)输出结果是原输入的一种排列、或是重组。

(2)被排序的对象-文件被排序的对象--文件由一组记录组成。

记录则由若干个数据项(或域)组成。

其中有一项可用来标识一个记录,称为关键字项。

该数据项的值称为关键字(Key)。

(3)排序运算的依据--关键字关键字,可以是数字类型,也可以是字符类型。

关键字的选取应根据问题的要求而定。

2.排序的分类1)按是否涉及内外存交换:(1) 内部排序:待排序的记录全部存放在内存中进行排序的过程。

(2) 外部排序:待排序的记录的数量很大,以至于内存不能容纳全部记录,在排序过程中需要对外存进行访问的排序过程。

2) 按策略划分内部排序方法(1) 插入排序:直接插入排序,折半插入排序;(2) 选择排序:快速排序,冒泡排序;(3) 交换排序:简单选择排序,堆排序;(4) 归并排序:归并排序;(5) 分配排序:基数排序;3)按稳定性划分内部排序(1)稳定排序:直接插入排序,冒泡排序,归并排序,基数排序(2)不稳定排序:简单选择排序,希尔排序,快速排序,堆排序3.内部排序算法的操作大多数排序算法都有两个基本的操作:比较和移动;(1) 比较两个关键字的大小;(2) 改变指向记录的指针或移动记录本身。

十大经典排序算法总结

十大经典排序算法总结

⼗⼤经典排序算法总结最近⼏天在研究算法,将⼏种排序算法整理了⼀下,便于对这些排序算法进⾏⽐较,若有错误的地⽅,还请⼤家指正0、排序算法说明0.1 排序术语稳定:如果a=b,且a原本排在b前⾯,排序之后a仍排在b的前⾯不稳定:如果a=b,且a原本排在b前⾯,排序之后排在b的后⾯时间复杂度:⼀个算法执⾏所耗费的时间空间复杂度:⼀个算法执⾏完所需内存的⼤⼩内排序:所有排序操作都在内存中完成外排序:由于数据太⼤,因此把数据放在磁盘中,⽽排序通过磁盘和内存的数据传输才能进⾏0.2算法时间复杂度、空间复杂度⽐较0.3名词解释n:数据规模k:桶的个数In-place:占⽤常数内存,不占⽤额外内存Out-place:占⽤额外内存0.4算法分类1.冒泡排序冒泡排序是⼀种简单的排序算法。

它重复地⾛访过要排序的数列,⼀次⽐较两个元素,如果它们的顺序错误就把它们交换过来。

⾛访数列的⼯作是重复地进⾏直到没有再需要交换,也就是说该数列已经排序完成。

这个算法的名字由来是因为越⼩的元素会经由交换慢慢“浮”到数列的顶端1.1算法描述⽐较相邻的元素,如果前⼀个⽐后⼀个打,就交换对每⼀对相邻元素做同样的⼯作,从开始第⼀对到结尾最后⼀对,这样在最后的元素应该会是最⼤的数针对所有的元素重复以上的步骤,除了最后⼀个重复步骤1-3,知道排序完成1.2动图演⽰1.3代码实现public static int[] bubbleSort(int[] array) {if (array.length == 0)return array;for (int i = 0; i < array.length; i++)for (int j = 0; j < array.length - 1 - i; j++)if (array[j + 1] < array[j]) {int temp = array[j + 1];array[j + 1] = array[j];array[j] = temp;}return array;}1.4算法分析最佳情况:T(n) = O(n) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2)2.选择排序表现简单直观的最稳定的排序算法之⼀,因为⽆论什么数据都是O(n2)的时间复杂度,⾸先在未排序序列中找到最⼩(⼤)元素,与数组中第⼀个元素交换位置,作为排序序列的起始位置,然后再从剩余未排序元素中继续寻找最⼩(⼤)的元素,与数组中的下⼀个元素交换位置,也就是放在已排序序列的末尾2.1算法描述1.初始状态:⽆序区为R[1..n],有序区为空2.第i躺排序开始时,当前有序区和⽆序区R[1..i-1]、R[i..n]3.n-1趟结束,数组有序化2.2动图演⽰2.3代码实现public static int[] selectionSort(int[] array) {if (array.length == 0)return array;for (int i = 0; i < array.length; i++) {int minIndex = i;for (int j = i; j < array.length; j++) {if (array[j] < array[minIndex]) //找到最⼩的数minIndex = j; //将最⼩数的索引保存}int temp = array[minIndex];array[minIndex] = array[i];array[i] = temp;}return array;}2.4算法分析最佳情况:T(n) = O(n2) 最差情况:T(n) = O(n2) 平均情况:T(n) = O(n2)3、插⼊排序是⼀种简单直观的排序算法,通过构建有序序列,对于未排序序列,在已排序序列中从后向前扫描,找到相应位置并插⼊,需要反复把已排序元素逐步向后挪位,为最新元素腾出插⼊空间3.1算法描述1.从第⼀个元素开始,该元素可以认为已经被排序2.取出下⼀个元素(h),在已排序的元素序列中从后往前扫描3.如果当前元素⼤于h,将当前元素移到下⼀位置4.重复步骤3,直到找到已排序的元素⼩于等于h的位置5.将h插⼊到该位置6.重复步骤2-53.2动图演⽰3.3代码实现public static int[] insertionSort(int[] array) {if (array.length == 0)return array;int current;for (int i = 0; i < array.length - 1; i++) {current = array[i + 1];int preIndex = i;while (preIndex >= 0 && current < array[preIndex]) {array[preIndex + 1] = array[preIndex];preIndex--;}array[preIndex + 1] = current;}return array;}3.4算法分析最佳情况:T(n) = O(n) 最坏情况:T(n) = O(n2) 平均情况:T(n) = O(n2)4、希尔排序是简单插⼊排序经过改进之后的⼀个更⾼效的版本,也称为缩⼩增量排序,同时该算法是冲破O(n2)的第⼀批算法之⼀。

算法_八大排序算法总结

算法_八大排序算法总结

算法_⼋⼤排序算法总结最近笔试⾯试中经常考到排序算法,及其对应的时间复杂度和空间复杂度分析,现做如下总结。

⼀,冒泡排序思想:对于0~n-1,依次⽐较相邻两个数,前者⽐后者⼤就交换,⼀轮后A[n-1]是最⼤数,在对0~n-2执⾏以上步骤,则A[n-2]是第⼆⼤的数,循环执⾏上⾯的步骤即可,形象的可以理解为⼤的数⼀个个冒到后⾯去,所以叫冒泡排序。

⽰意图:⾸先6和3⽐较,6⽐3⼤,交换6和5⽐较,交换6和7⽐较,不⽤交换依次执⾏以上步骤,第⼀轮后,序列变为接着,在0到n-2上执⾏以上步骤⼀轮过后,则变为依次执⾏以上步骤,最后序列为时间复杂度: O(n^2)空间复杂度:O(1)代码:1class BubbleSort {2public:3int* bubbleSort(int* A, int n)4 {5int temp;6// write code here7for(int i = 0; i < n; i++)8 {9for(int j = 0; j < n - i - 1; j++)10 {11if(A[j] > A[j+1])12 {13 temp = A[j];14 A[j] = A[j + 1];15 A[j + 1] = temp;16 }17 }1819 }20return A;21 }22 };⼆,选择排序思想:在序列中依次选择最⼩值放到最前端,重复以上步骤,只到排序完成⽰意图:最⼩数为0,放到最前端1到n-1最⼩数为1,放到最前端依次执⾏以上步骤,最后为时间复杂度:O(n^2)空间复杂度:O(1)代码:1class SelectionSort {2public:3int* selectionSort(int* A, int n)4 {5// write code here6//从前往后依次放⼊为排序的数组的最⼩值7int min_b;8int temp;9for(int i = 0; i < n - 1; i++)10 {11 min_b = i;12for(int j = i; j < n; j++) //寻找最⼩值13 {14if(A[min_b] > A[j])15 min_b = j;1617 }18 temp = A[i];19 A[i] = A[min_b];20 A[min_b] = temp;21 }22return A;23 }24 };三,插⼊排序思想:对于数组A[n],保证前⾯的A[0]~A[m]是排序好的,再把A[m+1]插⼊到前⾯排好序的序列中,m递增,知道m=n-2⽰意图:原始序列为:6和5⽐较,6⽐5⼤,要交换接下来把3插⼊到前⾯排好序的序列中,⾸先3和6⽐,6⼤,后移⼀位接着3和5⽐较,5⼤,后移⼀位只到前⾯没有数了,或者前⾯的数⽐要插⼊的数⼩,就在对应的位置插⼊该数再对1执⾏以上步骤重复以上步骤,只到整个序列排序完成时间复杂度:O(n^2)空间复杂度:O(1)代码1class InsertionSort {2public:3int* insertionSort(int* A, int n)4 {5// write code here6int temp;7for(int i = 1; i < n; i ++)8 {9 temp = A[i];10for(int j = i - 1; j >= 0; j--)11 {12if(temp < A[j])13 {14 A[j + 1] = A[j];15if(j == 0)16 {17 A[j] = temp;18 }19 }20else21 {22 A[j + 1] = temp;23break;24 }25 }26 }27return A;28 }29 };四,归并排序思想:对数组中每个数看成是长度为1的有序区间,接着合并相邻两个长度为1的有序区间,变为长度为2的有序区间,接着合并相邻长度为2的有序区间变成长度为4的有序区间,依次进⾏,只到排序完成⽰意图:⾸先为长度为1的有序区间合并为长度为2的有序区间合并为长度为4的有序区间合并为长度为8的有序区间,排序完成时间复杂度:O(nlogn)空间复杂度:O(N)代码1class MergeSort {2public:3int* mergeSort(int* A, int n)4 {5 mergeSort(A,0,n-1);6return A;78 }9void mergeSort(int* A, int left, int right)10 {11if(left == right)12return;13int mid=(left+right)/2;14 mergeSort(A,left,mid);15 mergeSort(A,mid+1,right);16 merge_p(A,left,mid,right);17return;18 }1920void merge_p(int* A, int left, int mid, int right)21 {22int* temp = new int[right - left + 1];23int l = left;24int r = mid + 1;25int k = 0;26while(l <= mid && r <= right)27 {28if(A[l] < A[r])29 temp[k++] = A[l++];30else31 temp[k++] = A[r++];32 }33while(l <= mid)34 temp[k++] = A[l++];35while(r <= right)36 temp[k++] = A[r++];37for(int i = 0; i < k; i++)38 {39 A[left + i] = temp[i];40 }41 }4243 };五,快速排序思想:随机选择数组中的数,⼩于等于这个数的放在左边,⼤于这个数的放在右边,递归调⽤以上步骤,完成排序⽰意图:⾸先随机选择,划分区间递归调⽤,即可完成排序。

八种基本排序及其空间复杂度

八种基本排序及其空间复杂度

八种基本排序及其空间复杂度排序,听起来就像是让东西乖乖排队一样,没错,这就是它的意思!在这个信息爆炸的时代,数据多得让人眼花缭乱,排序就是让我们把这些数据变得整齐划一的好帮手。

今天,我们来聊聊八种基本的排序方法,当然也顺便说说它们的空间复杂度,别担心,我会尽量让这段旅程轻松愉快,保证你听了不打瞌睡。

冒泡排序,名字听起来是不是很萌?就像泡泡一样,慢慢浮上来。

它的原理简单得令人发笑,两两比较,把较大的“泡泡”往后推,简直像是在给小朋友们上课,让他们学会乖乖排队。

可这家伙慢得要命,特别是在数据量大的时候,简直像是乌龟赛跑,空间复杂度只有O(1),真是个勤俭节约的小家伙。

再来就是选择排序,顾名思义,它喜欢选择最小的那个,然后把它放到前面。

就像逛超市时,你每次都挑最便宜的商品,心里想着“哎呀,这个买了肯定划算!”但是,这货也慢得让人抓狂,时间复杂度是O(n^2),但是空间复杂度还是O(1),让我们知道选择固然重要,但速度更重要啊!插入排序就像是老派的舞会,大家一个个走上舞台,找到自己的位置。

刚开始,可能有点笨拙,但一旦上手,嘿,效率可高了。

尤其是在小数据量的时候,简直就像刀切黄油,流畅得不得了。

它的空间复杂度同样是O(1),这小子真是能省就是能省,值得点赞!然后,我们得聊聊快速排序,这个家伙可不简单。

它聪明地选择一个“基准”,然后把比它小的放一边,大的放另一边,瞬间就像变魔术一样。

时间复杂度在平均情况下是O(n log n),空间复杂度是O(log n),哎呀,这小子真的是神乎其神,仿佛在说:“看,我多聪明!”再说说归并排序,这是一种比较优雅的排序方式,仿佛优雅的绅士走入舞会。

他先把数据分成小块,然后再慢慢合并,像拼图一样,最终把完整的画面呈现出来。

时间复杂度同样是O(n log n),但是它的空间复杂度可是O(n),得花费点空间来存放那些临时的数据。

然后有个小家伙叫希尔排序,这名字听上去有点高深,其实就是插入排序的升级版。

各种排序方法总结

各种排序方法总结

选择排序、‎快速排序、‎希尔排序、‎堆排序不是‎稳定的排序‎算法,冒‎泡排序、插‎入排序、归‎并排序和基‎数排序是稳‎定的排序算‎法。

‎冒泡法‎:这‎是最原始,‎也是众所周‎知的最慢的‎算法了。

他‎的名字的由‎来因为它的‎工作看来象‎是冒泡:‎复杂度为‎O(n*n‎)。

当数据‎为正序,将‎不会有交换‎。

复杂度为‎O(0)。

‎直接插‎入排序:O‎(n*n)‎选择排‎序:O(n‎*n)‎快速排序:‎平均时间复‎杂度log‎2(n)*‎n,所有内‎部排序方法‎中最高好的‎,大多数情‎况下总是最‎好的。

‎归并排序:‎l og2(‎n)*n‎堆排序:‎l og2(‎n)*n‎希尔排序‎:算法的复‎杂度为n的‎1.2次幂‎‎这里我没‎有给出行为‎的分析,因‎为这个很简‎单,我们直‎接来分析算‎法:首‎先我们考虑‎最理想的情‎况1.‎数组的大小‎是2的幂,‎这样分下去‎始终可以被‎2整除。

假‎设为2的k‎次方,即k‎=log2‎(n)。

‎2.每次‎我们选择的‎值刚好是中‎间值,这样‎,数组才可‎以被等分。

‎第一层‎递归,循环‎n次,第二‎层循环2*‎(n/2)‎.....‎.所以‎共有n+2‎(n/2)‎+4(n/‎4)+..‎.+n*(‎n/n) ‎= n+n‎+n+..‎.+n=k‎*n=lo‎g2(n)‎*n所‎以算法复杂‎度为O(l‎o g2(n‎)*n) ‎其他的情‎况只会比这‎种情况差,‎最差的情况‎是每次选择‎到的mid‎d le都是‎最小值或最‎大值,那么‎他将变成交‎换法(由于‎使用了递归‎,情况更糟‎)。

但是你‎认为这种情‎况发生的几‎率有多大?‎?呵呵,你‎完全不必担‎心这个问题‎。

实践证明‎,大多数的‎情况,快速‎排序总是最‎好的。

‎如果你担心‎这个问题,‎你可以使用‎堆排序,这‎是一种稳定‎的O(lo‎g2(n)‎*n)算法‎,但是通常‎情况下速度‎要慢于快‎速排序(因‎为要重组堆‎)。

排序算法总结

排序算法总结

排序算法总结导读:范文排序算法总结【篇一:排序算法总结】1、稳定排序和非稳定排序简单地说就是所有相等的数经过某种排序方法后,仍能保持它们在排序之前的相对次序,我们就说这种排序方法是稳定的。

反之,就是非稳定的。

比如:一组数排序前是a1,a2,a3,a4,a5,其中a2=a4,经过某种排序后为a1,a2,a4,a3,a5,则我们说这种排序是稳定的,因为a2排序前在a4的前面,排序后它还是在a4的前面。

假如变成a1,a4,a2,a3,a5就不是稳定的了。

2、内排序和外排序在排序过程中,所有需要排序的数都在内存,并在内存中调整它们的存储顺序,称为内排序;在排序过程中,只有部分数被调入内存,并借助内存调整数在外存中的存放顺序排序方法称为外排序。

3、算法的时间复杂度和空间复杂度所谓算法的时间复杂度,是指执行算法所需要的计算工作量。

一个算法的空间复杂度,一般是指执行这个算法所需要的内存空间。

功能:选择排序输入:数组名称、数组中元素个数算法思想简单描述:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

选择排序是不稳定的。

【篇二:排序算法总结】在计算机科学所使用的排序算法通常被分类为:计算的复杂度,依据列表的大小。

一般而言,好的性能是O,且坏的性能是O。

对于一个排序理想的性能是O。

仅使用一个抽象关键比较运算的排序算法总平均上总是至少需要O。

内存使用量稳定度:稳定排序算法会依照相等的关键维持纪录的相对次序。

也就是一个排序算法是稳定的,就是当有两个有相等关键的纪录R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前。

一般的方法:插入、交换、选择、合并等等。

交换排序包含冒泡排序和快速排序。

选择排序包含希尔排序和堆排序【篇三:排序算法的总结】基数、冒泡、插入、简单选择、归并是稳定的,快速、堆、希尔是不稳定的。

数据结构的常用算法

数据结构的常用算法

数据结构的常用算法一、排序算法排序算法是数据结构中最基本、最常用的算法之一。

常见的排序算法有冒泡排序、选择排序、插入排序、快速排序、归并排序等。

1. 冒泡排序冒泡排序是一种简单的排序算法,它重复地比较相邻的两个元素,如果它们的顺序错误就将它们交换过来。

通过多次的比较和交换,最大(或最小)的元素会逐渐“浮”到数列的顶端,从而实现排序。

2. 选择排序选择排序是一种简单直观的排序算法,它每次从待排序的数据中选择最小(或最大)的元素,放到已排序序列的末尾,直到全部元素排序完毕。

3. 插入排序插入排序是一种简单直观的排序算法,它将待排序的数据分为已排序区和未排序区,每次从未排序区中取出一个元素,插入到已排序区的合适位置,直到全部元素排序完毕。

4. 快速排序快速排序是一种常用的排序算法,它采用分治的思想,通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分小,然后再按此方法对这两部分数据进行快速排序,递归地进行,最终实现整个序列有序。

5. 归并排序归并排序是一种稳定的排序算法,它采用分治的思想,将待排序的数据分成若干个子序列,分别进行排序,然后将排好序的子序列合并成更大的有序序列,直到最终整个序列有序。

二、查找算法查找算法是在数据结构中根据给定的某个值,在数据集合中找出目标元素的算法。

常见的查找算法有线性查找、二分查找、哈希查找等。

1. 线性查找线性查找是一种简单直观的查找算法,它从数据集合的第一个元素开始,依次比较每个元素,直到找到目标元素或遍历完整个数据集合。

2. 二分查找二分查找是一种高效的查找算法,它要求数据集合必须是有序的。

通过不断地将数据集合分成两半,将目标元素与中间元素比较,从而缩小查找范围,最终找到目标元素或确定目标元素不存在。

3. 哈希查找哈希查找是一种基于哈希表的查找算法,它通过利用哈希函数将目标元素映射到哈希表中的某个位置,从而快速地找到目标元素。

三、图算法图算法是解决图结构中相关问题的算法。

排序算法记忆口诀

排序算法记忆口诀

排序算法的记忆口诀
排序算法的记忆口诀有很多,以下是几个常见的口诀:
“稳定不稳定,同序归并合”
“稳定不稳定”:指稳定性不同的排序算法。

“同序归并合”:指同序元素的归并排序和合并排序。

“小根堆,大根堆,冒泡排序不用追”
“小根堆,大根堆”:指小根堆和大根堆两种数据结构。

“冒泡排序不用追”:指冒泡排序是一种稳定的排序算法。

“选择排序找最小,插入排序插到底”
“选择排序找最小”:指选择排序是一种在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置的排序算法。

“插入排序插到底”:指插入排序是一种将待排序元素逐个插入到已排序序列中的排序算法。

“希尔排序去括号,归并排序来整合”
“希尔排序去括号”:指希尔排序是一种通过比较相距一定间隔的元素来工作的排序算法。

“归并排序来整合”:指归并排序是一种采用分治法的排序算法。

【十大经典排序算法(动图演示)】 必学十大经典排序算法

【十大经典排序算法(动图演示)】 必学十大经典排序算法

【十大经典排序算法(动图演示)】必学十大经典排序算法0.1 算法分类十种常见排序算法可以分为两大类:比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。

非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

0.2 算法复杂度0.3 相关概念稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。

不稳定:如果a原本在b的前面,而a=b,排序之后a 可能会出现在b 的后面。

时间复杂度:对排序数据的总的操作次数。

反映当n变化时,操作次数呈现什么规律。

空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

1、冒泡排序(Bubble Sort)冒泡排序是一种简单的排序算法。

它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。

走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

1.1 算法描述比较相邻的元素。

如果第一个比第二个大,就交换它们两个;对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;针对所有的元素重复以上的步骤,除了最后一个;重复步骤1~3,直到排序完成。

1.2 动图演示1.3 代码实现1.unction bubbleSort(arr) {2. varlen = arr.length;3. for(vari = 0; i arr[j+1]) {// 相邻元素两两对比6. vartemp = arr[j+1];// 元素交换7. arr[j+1] = arr[j];8. arr[j] = temp;9. }10. }11. }12. returnarr;13.}2、选择排序(Selection Sort)选择排序(Selection-sort)是一种简单直观的排序算法。

8种排序算法

8种排序算法

J=2(38) [38 49] 65 97 76 13 27 49
J=3(65) [38 49 65] 97 76 13 27 49
J=4(97) [38 49 65 97] 76 13 27 49
J=5(76) [38 49 65 76 97] 13 27 49
2. 堆的定义: N个元素的序列K1,K2,K3,...,Kn.称为堆,当且仅当该序列满足特性:
Ki≤K2i Ki ≤K2i+1(1≤ I≤ [N/2])
堆实质上是满足如下性质的完全二叉树:树中任一非叶子结点的关键字均大于等于其孩子结点的关键字。例如序列10,15,56,25,30,70就是一个堆,它对应的完全二叉树如上图所示。这种堆中根结点(称为堆顶)的关键字最小,我们把它称为小根堆。反之,若完全二叉树中任一非叶子结点的关键字均大于等于其孩子的关键字,则称之为大根堆。
(6)基数排序
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序,最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。基数排序基于分别排序,分别收集,所以其是稳定的排序算法。
2. 排序过程:
【示例】:
初始关键字 [49 38 65 97 76 13 27 49]
第一趟排序后 13 [38 65 97 76 49 27 49]
第二趟排序后 13 27 [65 97 76 49 38 49]
第三趟排序后 13 27 38 [97 76 49 65 49]
其次,说一下稳定性的好处。排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。基数排序就是这样,先按低位排序,逐次按高位排序,低位相同的元素其顺序再高位也相同时是不会改变的。另外,如果排序算法稳定,对基于比较的排序算法而言,元素交换的次数可能会少一些(个人感觉,没有证实)。

c语言、数据结构中的8种排序分析与代码

c语言、数据结构中的8种排序分析与代码

8种排序一、冒泡排序(小者上扬原则)已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。

首先比较a[1]与a[2]的值,若a[1]大于a[2]则交换两者的值,否则不变。

再比较a[2]与a[3]的值,若a[2]大于a[3]则交换两者的值,否则不变。

再比较a[3]与a[4],以此类推,最后比较a[n-1]与a[n]的值。

这样处理一轮后,a[n]的值一定是这组数据中最大的。

再对a[1]~a[n-1]以相同方法处理一轮,则a[n-1]的值一定是a[1]~a[n-1]中最大的。

再对a[1]~a[n-2]以相同方法处理一轮,以此类推。

共处理n-1轮后a[1]、a[2]、……a[n]就以升序排列了。

优点:稳定,比较次数已知;缺点:慢,每次只能移动相邻两个数据,移动数据的次数多。

初始关键字[49 38 65 97 76 13 27 49]第一趟排序后[38 49 65 76 13 27 49] 97第二趟排序后[38 49 65 13 27 49] 76 97第三趟排序后[38 49 13 27 49] 65 76 97第四趟排序后[38 13 27 49] 49 65 76 97第五趟排序后[38 13 27] 49 49 65 76 97第六趟排序后[13 27]38 49 49 65 76 97第七趟排序后[13] 27 38 49 49 65 76 97最后排序结果13 27 38 49 49 76 76 97#include <iostream>using namespace std;void main(){int i,j,k;int a[8]={49,38,65,97,76,13,27,49};for(i=7;i>=0;i--){for(j=0;j<i;j++){if(a[j]>a[j+1]){k=a[j];a[j]=a[j+1];a[j+1]=k;}}}for(i=0;i<8;i++)cout<<a[i]<<endl;}二、选择排序①初始状态:无序区为R[1..n],有序区为空。

十大经典排序算法-C语言

十大经典排序算法-C语言

十大经典排序算法(动图演示,收藏好文)0.1 算法分类十种常见排序算法可以分为两大类:非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序。

线性时间非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较类排序。

0.2 算法复杂度0.3 相关概念稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。

不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。

时间复杂度:对排序数据的总的操作次数。

反映当n变化时,操作次数呈现什么规律。

空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

1冒泡排序是一种简单的排序算法。

它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。

走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

1.1 算法描述▪比较相邻的元素。

如果第一个比第二个大,就交换它们两个;▪对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;▪针对所有的元素重复以上的步骤,除了最后一个;▪重复步骤1~3,直到排序完成。

1.2 动图演示1.3 代码实现function bubbleSort(arr) {var len = arr.length;for (var i = 0; i < len - 1; i++) {for (var j = 0; j < len - 1 - i; j++) {if (arr[j] > arr[j+1]) { // 相邻元素两两对比var temp = arr[j+1]; // 元素交换arr[j+1] = arr[j];arr[j] = temp;}}}return arr;}2选择排序(Selection-sort)是一种简单直观的排序算法。

数据结构--排序算法介绍

数据结构--排序算法介绍

数据结构--排序算法总结概述排序的分类:内部排序和外部排序内部排序:数据记录在内存中进行排序外部排序:因排序的数据量大,需要内存和外存结合使用进行排序这里总结的八大排序是属于内部排序:当n比较大的时候,应采用时间复杂度为(nlog2n)的排序算法:快速排序、堆排序或归并排序。

其中,快速排序是目前基于比较的内部排序中被认为最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短。

———————————————————————————————————————————————————————————————————————插入排序——直接插入排序(Straight Insertion Sort)基本思想:将一个记录插入到已排序好的有序表中,从而得到一个新的,记录数增1的有序表。

即:先将序列的第1个记录看成一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。

要点:设立哨兵,用于临时存储和判断数组边界直接插入排序示例:插入排序是稳定的,因为如果一个带插入的元素和已插入元素相等,那么待插入元素将放在相等元素的后边,所以,相等元素的前后顺序没有改变。

算法实现:[cpp]view plain copy1.#include<iostream>ing namespace std;3.4.void print(int a[], int n ,int i)5.{6. cout<<i<<":";7.for(int j= 0; j<8; j++){8. cout<<a[j] <<" ";9. }10. cout<<endl;11.}12.13.void InsertSort(int a[],int n)14.{15.int i,j,tmp;16.for(i=1;i<n;++i)17. {18.// 如果第i个元素大于第i-1个元素,直接插入19.// 否则20.// 小于的话,移动有序表后插入21.if(a[i]<a[i-1])22. {23. j=i-1;24. tmp=a[i]; // 复制哨兵,即存储待排序元素25. a[i]=a[i-1]; // 先后移一个元素26.while(tmp<a[j])27. {28.// 哨兵元素比插入点元素小,后移一个元素29. a[j+1]=a[j];30. --j;31. }32. a[j+1]=tmp; // 插入到正确的位置33. }34. print(a,n,i); // 打印每一趟排序的结果35. }36.}37.38.int main()39.{40.int a[8]={3,1,5,7,3,4,8,2};41. print(a,8,0); // 打印原始序列42. InsertSort(a,8);43.return 0;44.}分析:时间复杂度:O(n^2)———————————————————————————————————————————————————————————————————————插入排序——希尔排序(Shell Sort)基本思想:先将整个待排序的记录序列分割成为若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录依次进行直接插入排序。

八大排序详解

八大排序详解

八大排序详解八大排序算法包括插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序和基数排序。

1. 插入排序:这是一种简单直观的排序算法,其工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

在插入过程中,如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面,因此插入排序是稳定的。

2. 希尔排序:也称递减增量排序算法,是插入排序的一种更高效的改进版本。

3. 选择排序:它的工作原理是首先在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置,然后再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。

以此类推,直到所有元素均排序完毕。

4. 冒泡排序:这种排序算法会重复地遍历待排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

5. 归并排序:归并排序是一种采用分治法的排序算法。

它将待排序的序列分成若干个子序列,每个子序列单独进行排序,然后将已排序的子序列进行合并,得到最终的排序结果。

6. 快速排序:快速排序采用分治法进行排序。

在每一步中,它选择一个“基准”元素,并将数组分为两部分,其中一部分的所有元素都比基准元素小,另一部分的所有元素都比基准元素大。

然后,对这两部分独立地进行快速排序。

7. 堆排序:堆排序是一种树形选择排序,是对直接选择排序的有效改进。

堆是一种特殊的树形数据结构,它的每个父节点都大于或等于(小于或等于)其子节点(通常称为大顶堆或小顶堆)。

8. 基数排序:基数排序是一种非比较整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。

以上就是八大排序算法的详解,这些算法各有特点和使用场景,可以根据实际情况选择合适的算法。

15种排序算法

15种排序算法

15种排序算法
1. 冒泡排序 - 依次比较相邻元素的大小,将较大的数向后移动,直到没有交换
2. 选择排序 - 选择最小的元素,放到数组的起始位置,再从剩余元
素中选择最小的,以此类推
3. 插入排序 - 将一个元素插入已经排好序的序列中,从后向前比较
并移动元素
4. 希尔排序 - 将数组拆分成若干个子序列进行插入排序,缩小增量,直到增量为1
5. 归并排序 - 将数组分成两部分,分别排序,然后合并两个有序数

6. 快速排序 - 选取一个基准元素,将小于基准元素的放在左边,大
于基准元素的放在右边,然后分别对左右两边再递归快速排序
7. 堆排序 - 将数组建立一个最大/小堆,然后依次取出堆顶元素,再
将剩余元素重建堆
8. 计数排序 - 计算每个元素的出现次数,然后计算出每个元素应该
在排序后的序列中的位置
9. 桶排序 - 将元素分配到各个桶中,然后对每个桶进行排序,再依
次将各个桶中的元素输出到序列中
10. 基数排序 - 从低位到高位依次将元素排序,相同位上的元素按照
相同方式进行排序
11. 合并排序 - 将多个有序数组合并成一个有序数组,采用分治的思

12. 鸡尾酒排序 - 进行双向冒泡排序,先将最大的元素放到最后,再
将最小的元素放到前面,如此交替进行
13. 地精排序 - 选取一个随机数作为划分元素,将小于该随机数的元
素放在左边,大于该随机数的元素放在右边,然后对左右两边递归排

14. 跳跃表排序 - 利用跳跃表结构,快速查找元素并插入有序序列中
15. 非递归归并排序 - 利用非递归的方式实现归并排序,将序列分解成多个子序列,依次合并子序列。

常用的排序算法总结

常用的排序算法总结

常用的排序算法总结排序算法是计算机科学中的一项基本算法,它用于将一组数据按照一定的顺序进行排列。

常用的排序算法有多种,每种算法都有其特点和适用的场景。

下面将对常用的排序算法进行总结。

首先,插入排序是最基本的排序算法之一。

它的思想是从待排序的数据中逐个选择一个元素,并将其插入到已排序的序列中的合适位置。

插入排序的时间复杂度为O(n^2),对于小规模的数据来说,其性能还是相对较好的。

其次,选择排序也是一种简单且直观的排序算法。

它的思想是每次从待排序的数据中选择最小(或最大)的元素,并放到已排序序列的末尾。

选择排序的时间复杂度也是O(n^2),但相比插入排序,它少了一些元素比较和交换的操作,因此在某些情况下,选择排序可能更适合。

再次,冒泡排序是一种交换排序算法。

它的思想是依次比较相邻的两个元素,如果顺序不对,则交换它们的位置。

在每一轮的遍历过程中,最大(或最小)的元素会被交换到序列的末尾。

冒泡排序的时间复杂度也是O(n^2),但相对于选择排序和插入排序来说,它的性能较差。

此外,快速排序是一种常用且高效的排序算法。

它采用了分治的思想,通过递归地将序列划分为较小的子序列,并将子序列分别排序,最终合并起来得到有序序列。

快速排序的平均时间复杂度为O(nlogn),但在最坏情况下,时间复杂度可能达到O(n^2)。

另外,归并排序也是一种常用的排序算法。

它也是基于分治的思想,将序列划分为较小的子序列,然后分别对子序列进行排序,最后将排好序的子序列进行合并。

归并排序的时间复杂度始终为O(nlogn),并且它是一种稳定的排序算法。

还有,堆排序是一种利用二叉堆进行排序的算法。

它的思想是将待排序的数据看成是完全二叉树,并将其构建成一个最大(或最小)堆。

然后,每次将堆顶的元素移出,并调整堆使得剩下的元素仍然构成最大(或最小)堆。

堆排序的时间复杂度也是O(nlogn),并且它可以原地排序,不需要额外的空间。

最后,计数排序和桶排序是两种线性时间复杂度的排序算法。

八大排序算法

八大排序算法

算法实现: 我们简单处理增量序列:增量序列d = {n/2 ,n/4, n/8 .....1} n为要排序数的个数 即:先将要排序的一一组记录按某个增量d(n/2,n为要排序数的个数)分成若干干组子子序列,每组中记录的 下标相差d.对每组中全部元素进行行直接插入入排序,然后再用用一一个较小小的增量(d/2)对它进行行分组,在每 组中再进行行直接插入入排序。继续不断缩小小增量直至至为1,最后使用用直接插入入排序完成排序。 1. void print(int a[], int n ,int i){ 2. 3. 4. 5. 6. 7. } 8. 9. 10. 11. 12. 13. 14. 15. void ShellInsertSort(int a[], int n, int dk) 16. { 17. 18. 19. 20. 21. 22. for(int i= dk; i<n; ++i){ if(a[i] < a[i-dk]){ int j = i-dk; int x = a[i]; a[i] = a[i-dk]; while(x < a[j]){ } cout<<endl; cout<<i <<":"; for(int j= 0; j<8; j++){ cout<<a[j] <<" ";
操作方方法: 1. 选择一一个增量序列t1,t2,…,tk,其中ti>tj,tk=1; 2. 按增量序列个数k,对序列进行行k 趟排序; 3. 每趟排序,根据对应的增量ti,将待排序列分割成若干干长度为m 的子子序列,分别对各子子表进行行直接 插入入排序。仅增量因子子为1 时,整个序列作为一一个表来处理,表长度即为整个序列的长度。 希尔排序的示示例:

八种排序方法

八种排序方法

⼋种排序⽅法⼀.直接(选择)插⼊排序有两种⽅式:升序和降序我使⽤升序直接(简单)插⼊排序:每次向已经排序好的队列⾥⾯找个合适的位置,将值插⼊//笔试和⾯试://1.算法的描述 2.算法的实现 3.效率(时间复杂度和空间复杂度和稳定性)//稳定性定义:如果两个关键值A和A`,如果⼀开始A就在A`前⾯,你排序后A还在A`前⾯,我们就认为是稳定的//怎么看稳定性:看有没有跳跃交换直接插⼊排序:如果数组基本有序,我们就⽤直接插⼊排序,越有序,时间复杂度越⼩,极端情况下为O(n)时间复杂度O(n^2)空间复杂度O(1),稳定的为什么不⽤从前向后找:如果数组有序,则时间复杂度太⼤具体代码实现:#include <stdio.h>#include <assert.h>void InsertSort(int arr[], int len){//循环多少次个数-1//⽤临时量tmp保存关键值,从后向前找,⽐它⼩的或者⾛到了头,就将关键值放到下⼀个位置上assert(arr != NULL);if (NULL == arr)return;int count = 0;int tmp = 0;int j = 0;for (int i = 1; i < len; i++)//控制揭牌后需要排序的次数{tmp = arr[i];for (j = i - 1; j >= 0; j--)//从后向前找{if (arr[j] > tmp)//⽐关键值⼤,则向后移动{arr[j + 1] = arr[j];count++;}else{break;//找到了⽐它⼩的值退出}}arr[j + 1] = tmp;}printf("count %d\n", count);}void Show(int* arr, int len){assert(arr != NULL);if (NULL == arr)return;for (int i = 0; i < len; i++){printf("%d ", arr[i]);}printf("\n");}int main(){int arr[] = { 2,4,6,8,23,98,76,56,74,36,1,3,5,7,99,66,77,88 };InsertSort(arr, sizeof(arr) / sizeof(arr[0]));Show(arr, sizeof(arr) / sizeof(arr[0]));return0;}希尔shell排序:就是⼀种特殊的直接插⼊排序,只不过调⽤了很多次直接插⼊排序,按增量分组要求:增量最后⼀个必须为1,增量保持互素时间复杂度O(n^1.3~1.5),空间复杂度O(1) ,稳定性:发⽣了跳跃交换,所以不稳定例如:分成5组,处理之后的值:分成3组,处理之后的值:最后分成1组,处理之后的值:具体代码实现:#include <stdio.h>#include <assert.h>static void Shell(int arr[], int len, int gap)//gap 分成多少组(间隔){int tmp = 0;int j = 0;int count = 0;for (int i = gap; i < len; i++)//i开始的位置{tmp = arr[i];for (j = i - gap; j >= 0; j = j - gap){if (arr[j] > tmp){arr[j + gap] = arr[j];count++;}else{break;}}arr[j + gap] = tmp;}printf("%d count %d\n", gap, count);}void ShellSort(int arr[], int len){assert(arr != nullptr);if (NULL == arr)return;int dk[] = { 5, 3, 1 };for (int i = 0; i < sizeof(dk) / sizeof(dk[0]); i++){Shell(arr, len, dk[i]);}}void Show(int* arr, int len){assert(arr != NULL);if (NULL == arr)return;for (int i = 0; i < len; i++){printf("%d ", arr[i]);}printf("\n");}int main(){int arr2[] = { 2,4,6,8,23,98,76,56,74,36,1,3,5,7,99,66,77,88 };ShellSort(arr2, sizeof(arr2) / sizeof(arr2[0]));Show(arr2, sizeof(arr2) / sizeof(arr2[0]));return0;}⼆.交换排序冒泡(沉⽯)排序:两两⽐较,⼤的向后挪,⼩的向前挪时间复杂度O(n^2)空间复杂度O(1)稳定的具体代码实现://冒泡排序:两两⽐较,⼤的向后挪void BubbleSort(int arr[], int len){//assert/*int count=0;bool tag = true;*/int tmp = 0;for(int i=0; i<len-1; i++)//次数{//tag = true;for(int j=0;j+1<len-i; j++)//两两⽐较,⼤的向后挪{if(arr[j] > arr[j+1]){tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;//tag = false;}//count++;}/*if(tag){break;}*/}//printf("count = %d\n", count);}int main(){int arr[] = {2,4,6,8,23,98,76,56,74,36,1,3,5,7,99,66,77,88};BubbleSort(arr, sizeof(arr)/sizeof(arr[0]));Show(arr, sizeof(arr)/sizeof(arr[0]));return 0;}快速排序法每次找到基准值,以基准值为分界线,将数据分成两块,左边的数据都⽐基准值⼩,右边的数据都⽐基准值⼤快速排序,越有序越慢,规则:1.从右向左找⽐基准值⼩的数据,找到后,向左挪动2.从左向右找⽐基准值⼤的数据,找到后,向右挪动3.重复1,2,直到left == right,结束,将基准值放到arr[left] 或者arr[right]内缺点:越有序越慢,不稳定具体实现代码:#include<stdio.h>#include<assert.h>static int Partition(int arr[], int left, int right){int tmp = arr[left];while (left < right)//进来保证有两个值{while(left < right && arr[right] > tmp)right--;if(left == right){break;}arr[left] = arr[right];while(left < right && arr[left] <= tmp)left++;if(left == right){break;}arr[right] = arr[left];}arr[left] = tmp;//arr[right] = tmp;return left;//return right; 因为此时left == right}static void Quick(int arr[], int left, int right){if(left < right){//第⼀种优化:如果有效个数特别少,直接调⽤直接插⼊排序/*if(right-left+1<20 ) //⾃⼰设置有效个数{Insertsort(arr,left, high)return;} // Insertsirt表⽰⼀个插⼊排序类*///第⼆种优化:三数取中/*GetMiddleNumber(arr,left,mid,right);*///第三种优化:防⽌完全有序,⾃⼰打乱⼀下/*Swap(arr,start,rand()%(right-left+1)+start;*///第四种/*if(left < right){int midindex = Partition(arr, left, right);if(left < midindex-1){Quick(arr, left, midindex-1);}if(midindex+1 < right){Quick(arr, midindex+1, right);}}*/int midindex = Partition(arr, left, right);Quick(arr, left, midindex-1);Quick(arr, midindex+1, right);}}//⽤栈static void Quick_stack(int arr[], int left, int right){stack<int> st;if (left < right){int midindex = Partition(arr, left, right);if (left < midindex - 1){st.push(left);st.push(midindex - 1);}if (midindex + 1 < right){st.push(midindex + 1);st.push(right);}}while (!st.empty()){int q = st.top();st.pop();int p = st.top();st.pop();int midindex = Partition(arr, p, q);if (p < midindex - 1){st.push(p);st.push(midindex - 1);}if (midindex + 1 < q){st.push(midindex + 1);st.push(q);}}}void QuickSort(int arr[], int len)//时间复杂度O(nlogn)空间复杂度O(1)不稳定{//assertQuick_stack(arr, 0, len-1);}第⼀种优化代码:void InsertSort(int arr[], int left, int right){int tmp = arr[left];for (int i = left + 1; i <= right; i++){tmp = arr[i];int j = i - 1;while (j >= right && arr[i] > tmp){arr[j + 1] = arr[j];j--;}arr[j + 1] = tmp;}}第⼆种优化代码:void GetMiddleNumber(int arr[], int left, int right){if (arr[left] > arr[right]){Swap(arr, left, right);//交换左右端数据,保证左端较⼩}if (arr[mid] > arr[right]){Swap(arr, left, right);//交换中间和右边,保证中间较⼩}if (arr[mid] > arr[left]){Swap(arr, left, right);//交换中间和左端数据,保证左边不是最⼩的那⼀个}}第三种优化代码:Swap(arr, left, rand() % (end - start + 1) + start);//取⼀个⼩于有效长度随机值+最左端值的下标作为随机基准值的下标与start进⾏交换三.选择排序直接选择(简单选择排序):每次从待排序队列中找到最⼩值,和待排序队列的第⼀位交换即可时间复杂度O(n^2)空间复杂度O(1)不稳定的具体实现代码:#include<stdio.h>#include<assert.h>void SelectSort(int arr[], int len){assert(arr != NULL);if (NULL == NULL)return;int tmp = 0;for (int i = 0; i < len - 1; i++){int m= i;//存放最⼩值下标for (int j = i + 1; j < len ; j++){if (arr[j] <arr[m]){m = j;}}if (m != i)//if判断可省略{tmp = arr[m];arr[m] = arr[i];arr[i] = tmp;}}}void Show(int* arr, int len){assert(arr != NULL);if (NULL == arr)return;for (int i = 0; i < len; i++){printf("%d ", arr[i]);}printf("\n");}int main(){int arr[] = { 2,4,6,8,23,98,76,56,74,36,1,3,5,7,99,66,77,88 };SelectSort(arr, sizeof(arr) / sizeof(arr[0]));Show(arr, sizeof(arr) / sizeof(arr[0]));return 0;}堆排序:堆排序的时间复杂度O(nlogn)空间复杂度O(1)不稳定什么是堆?堆分为两种:⼤顶堆和⼩顶堆两个统称为堆⼤顶堆:⼀个⼆叉树,⽗节点的值⼤于⼦节点的值⼩顶堆:⼀个⼆叉树,⽗节点的值⼩于⼦节点的值什么是树形结构:⼆叉树,树根,深度,叶⼦结点,左孩⼦,右孩⼦,完全⼆叉树,满⼆叉树深度怎么求:log2n+1⼤顶堆和⼩顶堆的关系,和兄弟节点的值⽆关,只和⽗⼦节点有关调整2个要点:1.从最后⼀个⾮叶⼦节点⼦树开始从后向前调整2.调整的时候顺序是从上向下3.升序(⼤顶堆),降序(⼩顶堆)具体实现代码:#include<stdio.h>#include<assert.h>static void HeapAdjust(int arr[], int start, int end)//时间复杂度O(log2n)空间复杂度O(1){int tmp = arr[start];for(int i=2*start+1; i<=end; i=i*2+1)//i? 堆排序效率⾼体现在这⾥i=i*2+1{//1.左右孩⼦都存在//2.只有左孩⼦,没有右孩⼦if(i<end && arr[i] < arr[i+1])//通过i<end保证右孩⼦存在,且arr[i] <arr[i+1]保证左孩⼦⼩于右孩⼦ {i++;//这时候让i指向较⼤的右孩⼦下标}//if判断失败的话,要么没有右孩⼦,要么有右孩⼦但是左孩⼦⽐右孩⼦值⼤,所以i不需要改变if(arr[i] > tmp)//判断较⼤孩⼦节点的值是否⽐⽗节点的值⼤,⼤的话向上覆盖,不然就找到了合适位置 {arr[start] = arr[i];start = i;}else{break;//左右孩⼦中较⼤的孩⼦值⼩于tmp}}arr[start] = tmp;//有两种情况执⾏到这⼀⾏代码:1.触底 2.找到放tmp的合适位置}//堆排序的时间复杂度O(nlog2n)空间复杂度O(1)不稳定void HeapSort(int arr[], int len){//assert//2.调整为⼤顶堆for(int i=(len-1-1)/2; i>=0; i--)//O(nlog2n){HeapAdjust(arr, i, len-1);//}//第⼀个for循环⾛出来,这时已经为⼤顶堆了int tmp = 0;for(int j=0; j<len-1; j++)//j指的是循环的次数(顶部数据和最后⼀个节点交换的次数)//O(nlog2n){//3.将顶部数据和最后⼀个节点进⾏了交换tmp = arr[0];arr[0] = arr[len-1-j];arr[len-1-j] = tmp;//已经将顶部数据和最后⼀个节点进⾏了交换 //4.重复2.3操作HeapAdjust(arr, 0, (len-1-j)-1);}}void Show(int* arr, int len){assert(arr != NULL);if (NULL == arr)return;for (int i = 0; i < len; i++){printf("%d ", arr[i]);}printf("\n");}int main(){int arr[] = { 2,4,6,8,23,98,76,56,74,36,1,3,5,7,99,66,77,88 };HeapSort(arr, sizeof(arr) / sizeof(arr[0]));Show(arr, sizeof(arr) / sizeof(arr[0]));return0;}四.⼆路归并排序⼆路归并排序,⾮递归形式:将两个有序的段合并成⼀个有序的段,直到全部数据在同⼀个段内有序,则完成有序时间复杂度O(n log2n)空间复杂度O(1)稳定的具体代码实现://⼀次归并以gapgap合并static void Merge(int arr[], int len, int gap)//gap 标志⼏⼏合并{int *brr = (int*)malloc(sizeof(int) * len);assert(brr != NULL);int low1 = 0;int high1 = low1 + gap -1;int low2 = high1 + 1;int high2 = low2+gap-1<len ? low2+gap-1 : len-1;//H2 有可能越界若⼩于则low2+gap-1,不是则len-1int i = 0;while(low2 < len)//有两个有序段{while(low1 <= high1 && low2 <= high2)//两个段内头指针都没⾛到尾巴{if(arr[low1] <= arr[low2]){brr[i++] = arr[low1++];}else{brr[i++] = arr[low2++];}}//左边的段⾛到尾,那直接将右边的段内数据向下拷贝到brr内即可while(low2 <= high2){brr[i++] = arr[low2++];}//右边的段⾛到尾,那直接将左边的段内数据向下拷贝到brr内即可while(low1 <= high1){brr[i++] = arr[low1++];}//更改L1L2 H1H1,让指向接下来的两个有序段即可low1 = high2 + 1;high1 = low1+gap-1;low2 = high1 + 1;high2 = low2+gap-1<len ? low2+gap-1 : len-1;}//只有⼀个有序段while(low1 < len){brr[i++] = arr[low1++];}//将brr⾥的全部值拷贝到arr⾥⾯,然后将brr释放for(int j=0; j<len; j++){arr[j] = brr[j];}free(brr);brr = NULL;}void MergeSort(int arr[], int len)//控制合并次数{assert(arr != NULL);if(NULL == arr)return;for(int i=1; i<len; i*=2){Merge(arr, len, i);}}int main(){int arr[] = {2,4,6,8,23,98,76,56,74,36,1,3,5,7,99,66,77,88};MergeSort(arr, sizeof(arr)/sizeof(arr[0]));Show(arr, sizeof(arr)/sizeof(arr[0]));return0;}五.基数排序⼜称桶排序低位优先,所有数据从低位(个)位开始,依次放⼊到对应的⼗个桶内(队列中),再依次从桶中将数据依次取出(出队),直到所有数据循环次数和最⼤位数有关时间复杂度o(n) , 空间复杂度o(n)此时完全有序具体实现代码:#include<stdio.h>#include<assert.h>//基数排序//获取数组中最⼤值的位数static int Get_Figure(int arr[], int len) {int max = 0;for(int i=0; i<len; i++){if(arr[i] > max){max = arr[i];}}int count = 0;while(max != 0)max /= 10;}return count;}//获取n的第fin位的值//1234,2 = 2//234,0 = 4//12345,4 = 1//12345,7 = 0static int Get_num(int n, int fin){for(int i=0; i<fin; i++){n = n / 10;}return n % 10;//return n/(int)(pow((double)10, fin)) % 10;}//⽤⼆维数组调⽤static void Radix(int arr[], int len, int fin)//⼆维数组 fin判断的依据,到底是以什么位排序//时间复杂度O(n)空间复杂度O(n){int bucket[10][20] = {0};//桶int num[10] = {0};//对应的桶中有多少个有效值//所有的数据都以fin位为依据,放到了桶内for(int i=0; i<len; i++)//数组的下标从0开始放{int index = Get_num(arr[i], fin);//获取arr[i]的fin位的值,找到对应的桶bucket[index][num[index]] = arr[i];//放到对⽤的桶中第num[index]位上num[index]++;//对应的桶中有效个数++}//从0-9桶内依次取值到arr⾥int k = 0;for(int i=0; i<10; i++)//⼏号桶{for(int j=0; j<num[i]; j++)//j桶中有效值个数{arr[k++] = bucket[i][j];}}}//⽤链式队列调⽤static void Radix_queue(int arr[], int len, int fin)//时间复杂度O(n)空间复杂度O(n){LQueue queArr[10];for(int i=0; i<10; i++){InitLQueue(&queArr[i]);}for(int i=0; i<len; i++){int index = Get_num(arr[i], fin);Push(&queArr[index], arr[i]);}int k = 0;for(int i=0; i<10; i++){while(!IsEmpty(&queArr[i])){Pop(&queArr[i], &arr[k++]);}}for(int i=0; i<10; i++){Destroy(&queArr[i]);}}void RadixSort(int arr[], int len)//时间复杂度O(dn)空间复杂度(n)稳定{//assertint count = Get_Figure(arr, len);for(int i=0; i<count; i++)//循环的趟数,低位优先{Radix_queue(arr, len, i);}。

数据结构之——八大排序算法

数据结构之——八大排序算法

数据结构之——⼋⼤排序算法排序算法⼩汇总 冒泡排序⼀般将前⾯作为有序区(初始⽆元素),后⾯作为⽆序区(初始元素都在⽆序区⾥),在遍历过程中把当前⽆序区最⼩的数像泡泡⼀样,让其往上飘,然后在⽆序区继续执⾏此操作,直到⽆序区不再有元素。

这块是对⽼式冒泡排序的⼀种优化,因为当某次冒泡结束后,可能数组已经变得有序,继续进⾏冒泡排序会增加很多⽆⽤的⽐较次数,提⾼时间复杂度。

所以我们增加了⼀个标识变量flag,将其初始化为1,外层循环还是和⽼式的⼀样从0到末尾,内存循环我们改为从最后⾯向前⾯i(外层循环所处的位置)处遍历找最⼩的,如果在内存没有出现交换,说明⽆序区的元素已经变得有序,所以不需要交换,即整个数组已经变得有序。

(感谢@站在远处看童年在评论区的指正)#include<iostream>using namespace std;void sort(int k[] ,int n){int flag = 1;int temp;for(int i = 0; i < n-1 && flag; i++){flag = 0;for(int j = n-1; j > i; j--){/*下⾯这⾥和i没关系,注意看这块,从下往上travel,两两⽐较,如果不合适就调换,如果上来后⼀次都没调换,说明下⾯已经按顺序拍好了,上⾯也是按顺序排好的,所以完美!*/if(k[j-1] > k[j]){temp = k[j-1];k[j-1] = k[j];k[j] = temp;flag = 1;}}}}int main(){int k[3] = {0,9,6};sort(k,3);for(int i =0; i < 3; i++)printf("%d ",k[i]);}快速排序(Quicksort),基于分治算法思想,是对冒泡排序的⼀种改进。

快速排序由C. A. R. Hoare在1960年提出。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

八大排序算法总结
插入排序
1.直接插入排序
原理:将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序。

要点:设立哨兵,作为临时存储和判断数组边界之用。

实现:
Void InsertSort(Node L[],int length)
{
Int i,j;//分别为有序区和无序区指针
for(i=1;i<length;i++)//逐步扩大有序区
{
j=i+1;
if(L[j]<L[i])
{
L[0]=L[j];//存储待排序元素
While(L[0]<L[i])//查找在有序区中的插入位置,同时移动元素
{
L[i+1]=L[i];//移动
i--;//查找
}
L[i+1]=L[0];//将元素插入
}
i=j-1;//还原有序区指针
}
}
2.希尔排序
原理:又称增量缩小排序。

先将序列按增量划分为元素个数相同的若干组,使用直接插入排序法进行排序,然后不断缩小增量直至为1,最后使用直接插入排序完成排序。

要点:增量的选择以及排序最终以1为增量进行排序结束。

实现:
Void shellSort(Node L[],int d)
{
While(d>=1)//直到增量缩小为1
{
Shell(L,d);
d=d/2;//缩小增量
}
}
Void Shell(Node L[],int d)
{
Int i,j;
For(i=d+1;i<length;i++)
{
if(L[i]<L[i-d])
{
L[0]=L[i];
j=i-d;
While(j>0&&L[j]>L[0])
{
L[j+d]=L[j];//移动
j=j-d;//查找
}
L[j+d]=L[0];
}
}
}
交换排序
1.冒泡排序
原理:将序列划分为无序和有序区,不断通过交换较大元素至无序区尾完成排序。

要点:设计交换判断条件,提前结束以排好序的序列循环。

实现:
Void BubbleSort(Node L[])
{
Int i ,j;
Bool ischanged;//设计跳出条件
For(j=n;j<0;j--)
{
ischanged =false;
For(i=0;i<j;i++)
{
If(L[i]>L[i+1])//如果发现较重元素就向后移动
{
Int temp=L[i];
L[i]=L[i+1];
L[i+1]=temp;
Ischanged =true;
}
}
If(!ischanged)//若没有移动则说明序列已经有序,直接跳出
Break;
}
}
2.快速排序
原理:不断寻找一个序列的中点,然后对中点左右的序列递归的进行排序,直至全部序列排序完成,使用了分治的思想。

要点:递归、分治
实现:
选择排序
1.直接选择排序
原理:将序列划分为无序和有序区,寻找无序区中的最小值和无序区的首元素交换,有序区扩大一个,循环最终完成全部排序。

要点:
实现:
Void SelectSort(Node L[])
{
Int i,j,k;//分别为有序区,无序区,无序区最小元素指针
For(i=0;i<length;i++)
{
k=i;
For(j=i+1;j<length;j++)
{
If(L[j]<L[k])
k=j;
}
If(k!=i)//若发现最小元素,则移动到有序区
{
Int temp=L[k];
L[k]=L[i];
L[i]=L[temp];
}
}
}
2.堆排序
原理:利用大根堆或小根堆思想,首先建立堆,然后将堆首与堆尾交换,堆尾之后为有序区。

要点:建堆、交换、调整堆
实现:
Void HeapSort(Node L[])
{
BuildingHeap(L);//建堆(大根堆)
For(int i=n;i>0;i--)//交换
{
Int temp=L[i];
L[i]=L[0];
L[0]=temp;
Heapify(L,0,i);//调整堆
}
}
Void BuildingHeap(Node L[])
{ For(i=length/2 -1;i>0;i--)
Heapify(L,i,length);
}
归并排序
原理:将原序列划分为有序的两个序列,然后利用归并算法进行合并,合并之后即为有序序列。

要点:归并、分治
实现:
Void MergeSort(Node L[],int m,int n)
{
Int k;
If(m<n)
{
K=(m+n)/2;
MergeSort(L,m,k);
MergeSort(L,k+1,n);
Merge(L,m,k,n);
}
}
基数排序
原理:将数字按位数划分出n个关键字,每次针对一个关键字进行排序,然后针对排序后的序列进行下一个关键字的排序,循环至所有关键字都使用过则排序完成。

要点:对关键字的选取,元素分配收集。

实现:
Void RadixSort(Node L[],length,maxradix)
{
Int m,n,k,lsp;
k=1;m=1;
Int temp[10][length-1];
Empty(temp); //清空临时空间
While(k<maxradix) //遍历所有关键字
{
For(int i=0;i<length;i++) //分配过程
{
If(L[i]<m)
Temp[0][n]=L[i];
Else
Lsp=(L[i]/m)%10; //确定关键字
Temp[lsp][n]=L[i];
n++;
}
CollectElement(L,Temp); //收集
n=0;
m=m*10;
k++;
}
}。

相关文档
最新文档