排序算法合集(冒泡,选择,插入,堆排,快排)

1、冒泡排序

最初在学c语言时,老师就教的这个排序算法,原理比较简单:从数组下标为0处开始遍历,相邻之间进行比较,若a[i]>a[i+1],则exchange(a[i],a[i+1]),当然也可以将小的往后传递,将此过程不断进行,那么最后数组就有序了。

要点:(1)每遍历一遍,末尾就得到一个最大值(或最小值),那么接下来的遍历是不是每次都减少一个元素就好了,因为后边的已经排好序了啊。

(2)遍历n-1遍就排好序了,因为最后一遍只剩一个元素了,它一定放那儿,所以最后一遍就不用遍历了。

当然如果数据小,又懒得优化,多进行几遍也一样可以排序的,比如这样:

for(int i=0;i<n;i++){                              //遍历了n遍

for(int j=0;j<n-1;j++){                     //每次比较当前元素和下一个元素,所以循环结束条件为n-1

{

if(a[j]>a[j+1])

{    int t=a[j];

a[j]=a[j+1];

a[j+1]=t;    }

}

}

那么标准的冒泡排序,就是算法复杂度为n*(n-i)次也就是n^2如下:

for(int i=0;i<a.length-1;i++){                              //遍历n-1遍就够了

for(int j=0;j<a.length-i-1;j++){               //每次比较当前元素和下一个元素,每遍历一遍少比较一个元素,所以循环结束条件为n-i-1

{

if(a[j]>a[j+1])

{    int t=a[j];

a[j]=a[j+1];

a[j+1]=t;    }

}

}

2、选择排序

这个也是学c语言的时候和冒泡一起学的,它和冒泡算法复杂度一样,原理为:从数组下标为0处开始遍历,每次取出剩下元素的最大值(或最小值)放在当前位置,也就是说,第一次取最大的放第一个位置,第二次取次大的放第二个位置....执行n-1次就好了,最后一个只能放最后了。

标准选择排序代码如下:

for(int i=0;i<a.length-1;i++){               //遍历n-1遍就够了

int k=i;                                 //k为剩下元素中的最大值下标,初始化为当前位置

for(int j=i+1;j<a.length-1;j++){        //找出剩下元素中的最大值下标

if(a[j]>a[k])

k=j;

}

if(k!=i){                               //若最大值不是当前位置的值,则交换,每次将最大值放前边

int t=a[k];

a[k]=a[i];

a[i]=t;

}

}

3、插入排序

适用于较少元素时,效率比较高,原理:从数组下标为0处开始遍历,每次保证已经遍历的元素为有序序列,即每次将要遍历的数插入到前边数列的合适位置,保证已经遍历的元素为有序数列。如:遍历第一个元素,因为目前前边只有这一个元素,所以它是有序的,遍历第二个元素,和第一个元素比较,看它插在他前边还是后边,这样就保证已经遍历的元素都有序了,之后的类似,和前边的比较,然后插入合适的位置。

插入排序代码如下:

for(int i=1;i<a.length-1;i++){       //从下标1开始,一个元素的时候一定有序啊

int j=i-1;                          // j初始值为前一个元素,因为要将前边的元素一一和当前元素比较

int k=a[i];                         //记录当前位置元素的值,因为如果后边要移动的话会覆盖的

while(j>0&&a[j]>k){                //将大于当前元素值的都依次向前移一位,好空出适合的位置给当前元素值

a[j+1]=a[j];

j--;

}

a[j+1]=k;                          //因为j处元素值小于等于k (j处跳出循环的),所以k的适合位置为j+1

}

4、堆排序

要想理解堆排序,首先你要知道最大堆,要想理解最大堆,你得知道二叉树。

二叉树:每个节点最多有俩个孩子节点。

最大堆:父亲节点的值总是大于孩子节点的值。

当然在这里二叉树的存储结构不是链表,是使用数组存的:(1)数组下标为0处是根节点。

(2)父亲节点下标*2为左孩子下标,父亲节点下标*2+1为右孩子下标。

根据这俩条准则我们就可以将二叉树存在数组了。

堆排序原理:我们知道最大堆的性质(父亲节点的值总是大于孩子节点的值),那么根节点处不就是当前数列的最大值吗,那么我们每次取根节点的值放在末尾,然后将最大堆的大小-1,更新最大堆,取根节点放后边.....不断执行这个过程,直到最大堆中只剩一个元素,此时数组就是一个有序数组了。

根据原理可以看出我们需要编的操作有(1)建最大堆  (2)更新最大堆,其实建立最大堆就是不断更新最大堆的过程,如果我们将每个结点都执行一遍更新最大堆操作(即父亲节点的值总是大于孩子节点的值,不符合的话将父亲节点与最大的孩子交换位置),当然执行顺序必须是从下往上,然后只需从非叶子节点开始执行就好了(非叶子节点就是有孩子的结点)。

堆排序代码如下:

//更新最大堆操作

void dfDui(int x) {                         //参数为父亲节点下标

int lchild=x*2;                           //左孩子下标

int rchild=x*2+1;                         //右孩子下标

int max=x;                                //最大值下标初始为父亲下标

if(lchild<size&&a[lchild]>a[max])           //比较找出最大值

max=lchild;

if(rchild<size&&a[rchild]>a[max])

max=rchild;

if(max!=x){           //若父亲节点为最大值,则符合性质,否则交换,将最大值移到父亲节点处,然后因为孩子节点处已改变,更新此节点。

int t=a[max];

a[max]=a[x];

a[x]=t;

dfDui(max);

}

}

//建最大堆操作

void creatDui(){

for(int i=a.length/2+1;i>=0;i--){     //叶子结点数为结点总数一半且都在最后(可以从孩子节点下标的算法为父亲节点*2看出),因此                     duDui(i);                       // a.length/2+1处开始为非叶子节点

}

}

//堆排序操作

void sort(){

creatDui();                                //建最大堆

for(int i=size-1;i>=1;i--){               //每次将第一个数与最后一个数交换,然后大小-1,更新已经改变的根节点

int t=a[0];

a[0]=a[size-1];

a[size-1]=t;

size--;

dfDui(0);

}

}

5、快速排序

快速排序是实际运用中用的最多的算法,虽然它在最坏的情况下会达到n^2,但它的平均性能非常好,期望时间复杂度为nlgn,而且隐含的常数因子非常小,并且是原址排序。

快速排序原理:从一组数中任意选出一个数,将大于它的数放右边,小于它的数放左边,然后再从左边和右边的俩组数中分别执行此操作,知道组中元素数为1,此时,数组就是有序的了。

从原理中可以清楚的看出此操作为递归操作,其代码如下:

int partsort(int a[],int l,int r){                 //将比a[r]小的元素放左边,比它大的放右边,最后把a[r]放中间

int i=l;                                        //i为比a[r]大的元素的下标,初始为开始位置l

for(int j=l;j<r;j++){

if(a[j]<=a[r]){                               //如果元素比a[r]小则和大的元素交换位置,目的让小的放一起,大的放一起

int t=a[j];                                 //可以自己手运行几遍这个循环

a[j]=a[i];

a[i]=t;

i++;

}

}

int t=a[i];                                   //a[i]为小元素和大元素的交界处,将a[r]与之交换

a[i]=a[r];

a[r]=t;

return i;                                    //返回交界处下标,继续排前边的和后边的这俩组

}

void quicksort(int a[],int l,int r){

if(l<r){                                   //递归结束条件为组中只剩一个元素

int p=partsort(a,l,r);                    //分成俩组返回交界处

quicksort(a,l,p-1);                  //继续分左边

quicksort(a,p+1,r);

}

}

主函数中调用代码为,若数组大小为n,则:quicksort(a,0,n-1);

待续待续哈..........

时间: 2024-10-10 14:29:02

排序算法合集(冒泡,选择,插入,堆排,快排)的相关文章

自己动手实现数据结构——排序算法1(冒泡、插入、归并、简单选择)(C++实现)

冒泡排序 冒泡排序作为最简单的排序算法.两行for循环即可搞定. 步骤:一.从前到后依次比较相邻两个数大小,若是前面比后面大则将两个数交换位置,这样第一轮最大的一个数便会被交换到最后面. 二.重复一的步骤依次比较(但是最后一个数不需要参与比较,因为第一轮已经选出它最大),选出倒数第二大的. .... 三.直到所有的数都不需要比较则排序成功 例子就不举了,直接实现: buddle.cc #include<iostream> #include<vector> using namespa

排序算法合集

排序算法复习大致结束了,主要有以下几种:冒泡排序.选择排序.简单插入排序.希尔排序.归并排序.快速排序.堆排序. #include <iostream> #define MAXSIZE 1000 using namespace std; class SqList{ public: SqList():length(0){} SqList(int length1,int value=0):length(length1) { for(int i=0;i<length;++i) { data[i

排序算法复习:直接插入排序、堆排序、快排、冒泡排序

冒泡排序,感觉是最简单的排序: 基本思路:每次把数组中最小的一个元素像气泡一样浮动.固定到最顶端: 从前向后遍历数组,每次拿到一个元素,就执行一遍冒泡: 从数组末尾开始,到当前元素截止,从后向前遍历,每次比较数组中相邻的两个元素,如果后者比较小,就把两者互换. 这样经过第一次冒泡,可以把最小的元素『浮』到数组的首位.第二次冒泡会把第二小的元素『浮』到数组的第二位.直到所有的元素都被『浮动』到正确的位置. 代码极其简单: var BubbleSort = function (array) { va

排序算法整合(冒泡,插入,选择,归并算法)

package com.hcj.test; public class PaiXu { public static void main(String[] args) { /*int[] a = {33 , 22, 8, 17, 17, 18, 65, 44, -3, -5}; 选择排序 int[] result = xuanZePaiXu(a); 冒泡排序 int[] result = maoPaoPaiXu(a); 插入排序 int[] result = chaRuPaiXu(a);*/ //归

python排序算法实现(冒泡、选择、插入)

python排序算法实现(冒泡.选择.插入) python 从小到大排序 1.冒泡排序: O(n2) s=[3,4,2,5,1,9] #count = 0 for i in range(len(s)): for j in range((i+1),len(s)): s[i],s[j]=min(s[i],s[j]),max(s[i],s[j]) #print count print s 2.选择排序: O(n2) s=[3,4,2,5,1,9] #count = 0 for i in range(l

python 数据结构与算法之排序(冒泡,选择,插入)

目录 数据结构与算法之排序(冒泡,选择,插入) 为什么学习数据结构与算法: 数据结构与算法: 算法: 数据结构 冒泡排序法 选择排序法 插入排序法 数据结构与算法之排序(冒泡,选择,插入) 为什么学习数据结构与算法: 计算机重要的几门课: 1.数据结构和算法 2.网络 3.操作系统 4.计算组成原理 数据结构与算法: 算法: 衡量算法的标准: 时间复杂度:就是程序代码执行的大概次数 小结: 时间复杂度是用来估计算法运行时间的一个式子(单位) 一般来说,时间复杂度高的算法比复杂度低的算法慢 常见的

【数据结构】——排序算法——3.1、选择排序

      [数据结构]--排序算法--3.1.选择排序 一.先上维基的图: 分类 排序算法 数据结构 数组 最差时间复杂度 О(n2) 最优时间复杂度 О(n2) 平均时间复杂度 О(n2) 最差空间复杂度 О(n) total, O(1)auxiliary 二.描述: 选择算法算是最直观的一个了.每次在队列里抽取一个极大(或极小)值进行排列.每次都需要遍历未被抽取的元素队列. 三.Java程序: static void selection_sort(int[] unsorted) { for

topK问题最小堆和快排哪个快

最近一直纠结这个问题.看了很多帖子,决定自己写个例子,实测结果如下: 总数1万个取最大100,快排略快,最小堆偶尔快. 总数10万个取最大100,最小堆略快,快排偶尔快. 总数100万个取最大100,最小堆完胜,快排没戏,而且最小堆大概快了2倍. 总数1000万个取最大100,最小堆完虐,快排没戏,而且最小堆快了大概2倍. 结论:最小堆比快排优秀. 原因: 1.速度确实快. 2.最小堆不需要打乱原数据顺序,而快排会打乱.(并不是快的原因,而是最小堆的优点) 3.如果内存有限,无法加载所有数据,则

冒泡 选择 插入 希尔 堆 归并 快速 排序算法

排序相关概念 排序:对一序列对象根据某个关键字进行排序: 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面: 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面: 内排序:所有排序操作都在内存中完成: 外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行: 排序耗时的操作:比较.移动: 排序分类: (1)交换类:冒泡排序.快速排序:此类的特点是通过不断的比较和交换进行排序: (2)插入类:简单插入排序.希尔排序:此类的特点是通过插入的