十大经典排序算法(冒泡排序、选择排序、插入排序、希尔排序、归并排序、快排排序、堆排序、桶排序、计数排序、基数排序)

排序算法:
一、冒泡排序:
(1)原理:

  1、从第一个数据开始,与第二个数据相比较,如果第二个数据小于第一个数据,则交换两个数据的位置。

  2、指针由第一个数据移向第二个数据,第二个数据与第三个数据相比较,如果第三个数据小于第二个数据,则交换两个数据的位置。

  3、依此类推,完成第一轮排序。第一轮排序结束后,最大的元素被移到了最右面。

  4、依照上面的过程进行第二轮排序,将第二大的排在倒数第二的位置。

  5、重复上述过程,每排完一轮,比较次数就减少一次。

(2)例子:

待排序数据:7, 6, 9, 8, 5,1

	第一轮排序过程:指针先指向7,7和6比较,6<7,交换6和7的位置,结果为:6,7,9,8,5,1
	
	第二轮排序过程:指针指向第二个元素7,7和9比较,9>7,不用交换位置,结果仍为:6,7,9,8,5,1

	第三轮排序过程:指针指向第三个元素9,比较9和8,8<9,交换8和9的位置,结果为:6,7,8,9,5,1

	第四轮排序过程:指针指向第四个元素9,比较9和5,5<9,交换5和9,结果为:6,7,8,5,9,1

	第五轮排序过程:指针指向第五个元素9,比较9和1,1<9,交换1和9的位置,结果为6,7,8,5,1,9

二、选择排序
(1)原理:

  1、从第一个元素开始,分别与后面的元素向比较,找到最小的元素与第一个元素交换位置;

  2、从第二个元素开始,分别与后面的元素相比较,找到剩余元素中最小的元素,与第二个元素交换;

  3、重复上述步骤,直到所有的元素都排成由小到大为止。
	 3 11 6 10 2 5

     2 11 6 10 3 5
     2 3 6 10 11 5
     2 3 5 10 11 6
     2 3 5 6 11 10
     2 3 5 6 10 11

(2)思路:
 	需要两次循环,第一层循环表示每轮指针指向的位置,将最小值min初始化为第i个元素
 	第二层循环从j=i+1开始,分别与min比较,如果小于min,则更新min的值,
 	内层循环结束后,交换min元素和第i个元素的位置,以此类推进行下一轮循环,直到i=length时停止循环
 	当i=length时,说明小的元素已经全部移到了左面

三、插入排序
(1)原理:
1.将指针指向某个元素,假设该元素左侧的元素全部有序,将该元素抽取出来,
然后按照从左往右的顺序分别与其左边的元素比较,遇到比其大的元素便将元素右移,直到找到比该元素小的元素
或者找到最左边发现左侧元素都比自身大,停止

	2.此时出现一个空位,将该元素放入到空位中,此时该元素左侧的元素都比它小,右侧的元素都比它大

	3.指针向后移一位,重复上述过程,每操作一轮,左侧有序元素都增加一个,右侧无序元素都减少一个
	    【6 5 8 11 9 2 3 7】
	     5 6 8 11 9 2 3 7
	     5 6 8 11 9 2 3 7
	     5 6 8 11 9 2 3 7 
	     5 6 8 9 11 2 3 7
	     2 5 6 8 9 11 3 7
	     2 3 5 6 8 9 11 7 
	     2 3 5 6 7 8 9 11  
(2)实现:
    1.以数组的某一位作为分隔位,比如index=1,假设左面的都是有序的
    2.将index位的数据拿出来,放到临时变量里,这时index位置就空出来了
    3.从index-1开始将左面的数据与当前index位的数据(即临时变量temp)进行比较,如果array[index-1]>temp,
      则将array[index-1]后移一位,即array[index+1]=array[index-1],此时index-1就空出来了
    4.再用index-2(即index-1=index-2)位的数据和temp比,重复步骤3,
      直到找到<=temp的数据或者比到了最左面(说明temp最小),停止比较,将temp放在当前空的位置上
    5.index向后挪1,即index=index+1,temp=array[index],重复步骤2-4,直到index=array.length,排序结束,
      此时数组中的数据即为从小到大的顺序  

四、希尔排序
(1)原理:希尔排序属于插入类排序,是将整个有序序列分割成若干小的子序列分别进行插入排序。
排序过程:先取一个正整数d1 然后取d2 (2)实现:
选择一个增量序列d1,d2,…,di,di=1;
按增量序列个数k,对序列进行k 趟排序;
每趟排序,根据对应的增量di,将待排序列分割成若干长度为m的子序列,分别对各子表进行直接插入排序。仅增量因子为di = 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

 	例如:				8 9 1 7 2 3 5 4 6 0 
 	设增量为length/2=5
 	划分为5组:	         【8 3】,【9 5】,【1 4】,【7 6】,【2 0】
 	每组内进行插入排序:  【3 8】,【5 9】,【1 4】,【6 7】,【0 2】
 	第一趟排序:          3 5 1 6 0 8 9 4 7 2
 	增量为 5/2=2
 	划分为2组:          【3 1 0 9 7】,【5 6 8 4 2】
 	每组内进行插入排序:  【0 1 3 7 9】,【2 4 5 6 8】
 	第二趟排序:         0 2 1 4 3 5 7 6 9 8
 	增量为 2/2=1
 	划分为1组:          【0 2 1 4 3 5 7 6 9 8】
 	第三趟排序:         0 1 2 3 4 5 6 7 8 9

五、归并排序
(1)原理:归并排序的核心思想是将两个有序的数列合并成一个大的有序的序列。
通过递归,层层合并,即为归并。

	1.将一个序列拆分为左(L)右(R)两部分
	2.令指针p1指向L的起始元素,p2指向R的起始元素,i指向临时数组temp待合并部分的起始元素temp[0];
	3.若L[p1]≤R[p2],令temp[i]=L[p1],p1++,i++;
	否则,令temp[i]=R[p2],p2++,i++;

例如:
待排序序列:   18 5 7 14 25 12 6 24
第一趟排序后:  【5 18】 【7 14】 【12 25】 【6 24】
第二趟排序后:   【5 7 14 18】   【6 12 24 25】
第三趟排序后:   【5 6 7 12 14 18 24 25】

六、快排
(1)原理:分治法
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
(2)过程:
1、从数列中挑出一个元素,称为 “基准”(pivot),
2、重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3、递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

(3)实现:
	(1)给定一个用于比较的基准值,可以为数组的第一位或最后一位,或者随机在数组中取一位。
	初始序列:  3 7 6 4 1 0 9 8 2 5
	假设:5是基准值,从前往后比较,
	 11>5,放在5的右边即5,11
	 3<5,放在5的左边,即3,5,11
	 7>5,放在5的右边,即3,5,11,7
	 6>5,放在5的右边,即3,5,11,7,6
	 4<5,放在5的左边,即3,4,5,11,7,6
	 1<5,放在5的左边,即3,4,1,5,11,7,6
	 0<5,放在5的左边,即3,4,1,0,5,11,7,6
	 9>5,放在5的右边,即3,4,1,0,5,11,7,6,9
	 8>5,放在5的右边,即3,4,1,0,5,11,7,6,9,8
	 2<5,放在5的左边,即3,4,1,0,2,5,11,7,6,9,8
	 所以,第一次排序的结果为:【3,4,1,0,2】【5,11,7,6,9,8】
	 第二次排序再取一个基准值:2  8
	 排序结果为:【[1,0] [2,3,4]】 【[5,7,6] [8,11,9]】
	 依次类推........

七、堆排序
堆是一个关键码序列{k1,k2,k3…kn},满足:
ki<=k2i; ki<=k2i+1 或者 ki>=k2i; ki>=k2i+1

关键:第一个 关键点为如何构建堆结构?

	堆结构是一种树结构,也就是完全二叉树。在这个树中,每个结点对应于原数据的一个记录,并且每个结点应满足以下条件:
	(1)如果按照从小到大的顺序排序,要求非叶结点的数据要大于或等于其左、右子结点的数据
	(2)如果按照从大到小的顺序排序,要求非叶结点的数据要小于或等于其左右子结点的数据

	 第二个关键点为如何在输出堆顶元素之后,调整剩余元素为一个新的堆,并且堆顶为最大值?
 
过程:
	一个完整的堆排序需要经过反复的两个步骤:构造堆结构和堆排序输出
	构造堆结构就是把原始的无序数据按堆结构的定义进行调整,首先,需要将原始的无序数据放置到一个完全二叉树的各个结点中。然后,由完全二叉树的下层向上层逐层进行父子结点的数据进行比较,使父结点的数据大于子结点的数据,需要使用“筛选”进行结点数据的调整,直到所有结点最后满足堆结构的条件为止,筛选运算主要针对非叶结点进行调整。	 	
	
	筛选:自堆顶至叶子的调整大小的过程为筛选
	堆化过程:自下向上将非叶结点与他的左右子树的根结点进行比较,满足父结点大于子结点

八、桶排序
原理:将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序。

实现:	
	(1).设置一个定量的数组当做空桶
	(2).将桶分区,并将原数组中对应的值放入桶中
	(3).对每个不是空的桶内部再进行排序
	(4).遍历不是空的桶

九、计数排序
原理:计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数。然后根据数组C来将A中的元素排到正确的位置。它只能对整数进行排序。

实现:	
	(1).找出无序数组的最大值,创建一个长度为最大值+1的空数组
	(2).遍历原数组,统计每个元素出现的次数
	(3).遍历"桶",即用于元素个数统计的数组,得到有序的数组

十、基数排序
原理:基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

实现方法:
	最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。

	最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。

过程:
	(1).取得数组中的最大数,并取得位数
	(2).从最低位开始取每个位
	(3).将原数组里的每个数字放在相应的桶里
	(4).将桶里的数据覆盖到原数组中


总结: 
	基数排序:根据键值的每位数字来分配桶
  	计数排序:每个桶只存储单一键值
  	桶排序:每个桶存储一定范围的    

你可能感兴趣的:(算法,算法,数据结构,排序算法)