1、冒泡排序
首先在n个数中,从前到后依次比较相邻的两个数,如果前一个数大于后一个数,则交换位置,这样下来可以将n个数中最大的数移动到最后的位置;然后在前n-1个数中,继续上述操作,将第二大的数移动到倒数第二个位置。这样重复n-1次,就可以得到一个从小到大的序列。冒泡排序可以是稳定的,当设置当两个数大小相同则不交换位置时,可以保持序列的稳定性。
1 void bubble_sort_(vector<int> &q){ 2 for(int i = q.size() - 1; i > 0; i--){ 3 for(int j = 0; j < i; j++){ 4 if(q[j] > q[j+1]){ 5 swap(q[j], q[j+1]); 6 } 7 } 8 } 9 }
冒泡排序可以进行优化,这个优化还是蛮重要的,当在前i个数中都没有产生交换时,说明此时序列已经排好序了,那么可以直接break,如果知道是否产生了交换,我们可以设置一个flag,代码如下:
1 void bubble_sort_(vector<int> &q){ 2 for(int i = q.size() - 1; i > 0; i--){ 3 bool flag = false; 4 for(int j = 0; j < i; j++){ 5 if(q[j] > q[j+1]){ 6 swap(q[j], q[j+1]); 7 flag = true; 8 } 9 } 10 if(!flag) break; 11 } 12 }
2、选择排序
选择排序的思想是先在n个数中,选出一个最小的数,然后把它放到最前面,接着在剩下的数中,选出第二小的数,把它放到第二个位置,这样重复下去,直到所有的数都排好顺序。
1 void selection_sort_(vector<int> &q){ 2 for(int i = 0; i < q.size() - 1; i++){ 3 int min = i; 4 for(int j = i + 1; j < q.size(); j++){ 5 if(q[j] < q[min]){ 6 min = j; 7 } 8 } 9 swap(q[i], q[min]); 10 } 11 }
3、插入排序
插入排序的过程像打牌,当摸到一张新牌后,要在现有的牌中找到一个合适的位置,将新牌插进去。摸到的第一张牌认为是已排好序的,再摸第二张牌的时候,就要比较与第一张的大小然后插入,重复这个操作,直到所有牌都是有序的。插入排序的时间复杂度最坏为O(n2),当给定的待排序的序列是由大到小给出的时候;最好为O(n),当给定的序列已经是排好序的时候。插入排序是稳定的,当遇到相同数的时候,将新牌插入到相同牌的前面,可以保证其稳定性。
在插入排序中,我们将新牌由后往前进行比较,代码如下:
1 void insertion_sort(vector<int> &q){ 2 for(int i = 1; i < q.size(); i++){ 3 int t = q[i], j; 4 for(j = i-1; j >= 0; j--){ 5 if(q[j] > t){ 6 q[j+1] = q[j]; 7 } 8 else break; 9 } 10 q[j+1] = t; 11 } 12 }
需要注意第10行的下标界限是j+1,界定的办法有两种,一个是如果第二个循环完整的执行完毕没有break,此时j为-1,所以第10行下标一定为j+1。另一种办法是假设新牌比所有牌都大,第二个循环根本没执行,那么新牌肯定是放在最后的位置了,也就是j+1的位置。