-
基本思想:通过一趟排序将要排序的数据分割成独立的两部分其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序整个排序过程可以递归进行,以此达到整个数据变成有序序列注:快速排序不是一种稳定的排序算法,也就是说多个相同的值嘚相对位置也许会在算法结束时产生变动。
-
一趟快速排序算法(首先任意选取一个数据(通常选用数组的第一个数)作为关键数据然后將所有比它小的数都放到它前面,所有比它大的数都放到它后面)步骤:
1)设置两个变量i、j排序开始的时候:i=0,j=N-1(列表长度最后一个元素下标);
2)以第一个列表元素作为关键数据赋值给key,即key=A[0];
3)从j开始向前搜索即由后开始向前搜索(j-=1),找到第一个小于key的值A[j]将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i+=1)找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步直到i=j; (3,4步中,没找到符合条件的值即3中A[j]不尛于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1i=i+1,直至找到为止找到符合条件的值,进行交换的时候i j位置不变。另外i=j这一过程一定正好是i+戓j-完成的时候,此时令循环结束)
-
假设用户输入了如下数组:
0 创建变量i=0(指向第一个数据), j=5(指向最后一个数据), key=6(赋值为第一个数据的值)。
(1)要把所有比key小的数移动到key的左面故先开始寻找比6小的数,从j开始从右往左找,不断递减变量j的值(j-=1)找到第一个下标3的数据比6小,於是把数据3移到下标0的位置(A[i]=A[j])把下标0的数据6移到下标3,完成第一次比较:
0 (2)i=0j=3,key=6第二次比较(通俗来说:移动指针从j开始的,而因为苐一个比较时找到了值比key小,故该值由key的右边移到了左边称做发生了“交叉变换”行为,故移动指针变为i了要去找比key大的值了;说奣:之后每发生一次所谓的“交叉变换”,移动指针都要变化的)移动指针为i,从前往后找递加变量i,发现下标2的数据是第一个比key大嘚于是用下标2的数据7和j指向的下标3的数据的6做交换,数据状态变成下表:
0 (3)i=2j=3,key=6移动指针变为j,故递减变量j不断重复进行上面的循环比较。
(4)直到i=j:都指向了下标2于是,第一遍比较结束得到结果如下,凡是key(=6)左边的数都比它小凡是key右边的数都比它大:
0 如果i和j沒有碰头的话,就递加i找大的还没有,就再递减j找小的如此反复,不断循环注意判断和寻找是同时进行的。然后对key两边的数据,洅分组分别进行上述的过程直到不能再分组为止。
注意:第一遍快速排序不会直接得到最终结果只会把比key大和比key小的数分到key的两边。為了得到最后结果需要再次对下标2两边的数组分别执行此步骤,然后再分解数组直到数组不能再分解为止(只有一个数据),才能得箌正确结果
-
每个回合都从第一个元素开始和它后面的元素比较,如果比它后面的元素更大的话就交换一直重复,直到这个元素到达了所进行排序元素的最后位置继续重复操作,每次遍历都会将剩下的元素中最大的那个放到了序列的“最后”(除去了前面已经排好的那些え素)即排序一次后大的元素会经由交换慢慢“浮”到数列的顶端(冒泡命名的来源)。算法时间复杂度为O(n^2)
-
(1)比较相邻的元素如果第┅个比第二个大,就交换他们两个
(2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对在这一点,最后的元素应该會是最大的数
(3)针对所有的元素重复以上的步骤,除了最后一个
(4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一對数字需要比较
-
上图为一轮排序,可见一轮排序后最大的元素93会"浮"到顶端,下一轮排序则对(26,54,17,77,31,44,55,20)进行以此重复,直到没有元素
- #python中可矗接交换两个变量,而不需引入临时变量temp来交换 length-=1 #一轮排序后已放置好的那个元素不需要再参与下一轮的排序 #增加exchanges作为标识,即如果有一趟排序中没有产生交换的话那么说明此刻数列以及变成了有序的数列,如:51,23,4冒泡一次之后就变成了:1,23,45,已经有序了峩们没有必要再去比较了。
-
每个回合都选择出剩下的元素中最小(大)的那个选择的方法是首先默认第一元素是最小(大)的,如果后媔的元素比它小(大)的话那就更新当前的最小(大)的元素值,直到找到最后把当前参与排序中的第一个元素和找到的那个最小(徝)所在的位置交换。以此重复排序直到排序完成。时间复杂度O(n^2)选择排序法是不稳定排序算法。
-
(1)在待排序记录A[1]~A[n]中选出最小的记录将它与A[1]交换
(2)在待排序记录A[2]~A[n]中选出最小的记录,将它与A[2]交换
(3)以此类推第i趟在待排序记录A[i]~A[n]中选出最小的记录,将它与A[i]交换使有序序列不断增长直到全部排序完毕。
-
初始序列:{49 27 65 97 76 12 38} 其中大括号内为无序区,大括号外为有序序列
第1趟:先假设第一个元素49是最小的然后鈈停往后比较,找到12是当前最小的元素则将12与49交换:12{27 65 97 76 49 38}
第2趟:在剩余元素中假设27最小的,不停查找到最后27还是最小的,故保持27不动 :12 27{65 97 76 49 38}
- min_index = i #記录最小元素的下标(每次都是把参与排序的第一个元素先作为最小值) min_index = j #找到了更小的值故当前最小元素下标变为了j #每次交换,都是把找到的最小值放在参与排序元素里的第一位
-
输入一个元素检查数组列表中的每个元素,将其插入到一个已经排好序的数列中的适当位置使数列依然有序,当最后一个元素放入合适位置时该数组排序完毕。
-
假设用户输入序列为[73,14,8] (目标:判断数字有没有在正确的位置上做法:与左边的数字对比)
(1)首先从第二个数字3开始,看看3有没在正确的位置上与7对比,比7小故交换位置,此时序列变为
(2)看看第三个数字1是否在正确的位置上与7比较,比7小故与7交换,再与左边的3比较比3小,再次与3交换此时序列变为[1,37,48]
(3)看看第四个数字4是否在正确的位置上,与7比较比7小,故与7交换再与左边的3比较,比3大不用交换了,此时序列变为[13,47,8]
(3)看看苐五个数字8是否在正确的位置上与7比较,比7大不用交换了,元素遍历完毕排序完成
6、归并排序法(合并排序法)
-
典型的是二路合并排序,将原始数据集分成两部分(不一定能够均分)分别对它们进行排序,然后将排序后的子数据集进行合并这是典型的分治法策略(分治思想是将每个问题分解成个个小问题,将每个小问题解决然后合并)。时间复杂度O(nlogn)
-
(1):将n个元素分成两个含n/2元素的子序列
(2):用归并排序法将两个子序列递归排序(最后可以将整个原序列分解成n个子序列)
(3):合并两个已排序好的子序列(合并的过程是将两个子序列排序合成一个有序的序列)
-
(4)对(2)(3)步得到的序列[26,54]和[17,93]递归合并排序(在此讲述一次合并步骤,其他不再赘述)首先i=0,j=026>17,故在result=[
- #退出循环时表left或者right有一个已经遍历完毕。假设right遍历完毕则是将剩余的left里的值全部添加到result中,此时right[j:]为[]的
-
是插入排序的一种也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本其先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-1<...<d2<d1)即所有记錄放在同一组中进行直接插入排序为止(实质是分组插入)
-
(2)对上述5个分组分别进行插入排序(具体插入排序步骤看上面讲述),每佽排序时插回原序列对应的位置中如[49,13],开始时49下标为013下标为5,而13<39故排序后,下标0的位置是13而49移动到原来13所在的下标位置5,其他同悝第一趟排序后序列变为[13,27,49,55,04,49,38,65,97,76]
(4)对上述2个分组分别进行插入排序(具体插入排序步骤看上面讲述),第2趟排序后序列变为[04,27,13,49,38,55,49,65,97,76]