快速排序的核心思想能够参照分治三步法:前端
1.划分问题 把数组元素重排后分红左右两块,使得左边的元素都小于右边的元素ios
2.递归求解 再把左右两边分别排序算法
3.合并问题 不须要合并,由于数组已经有序后端
1 #include <iostream> 2 #include <cstdio> 3 #include <fstream> 4 using namespace std; 5 6 void quicksort(int a[],int left, int right) 7 { 8 if (left>=right) return; //递归结束 9 int mark = a[left]; //取第一个数为标志 10 int st = left; 11 int ed = right; 12 while(st<ed) 13 { 14 while(st<ed && a[ed] >= mark) ed--; //从末尾开始找比mark小的数 15 if (st<ed) a[st++] = a[ed]; //先移到前端,而后st再加一(挖洞) 16 while(st<ed && a[st] < mark) st++; //从开头找比mark大的数 17 if (st<ed) a[ed--] = a[st]; //先移到后端,而后ed再减一(填坑) 18 } 19 a[st] = mark; //将mark移到中间 20 quicksort(a,left,st-1); 21 quicksort(a,st+1,right); 22 } 23 24 int main() 25 { 26 ifstream fin("data.in"); 27 int num ; 28 int a[100]; 29 fin >> num ; 30 for (int i=0;i<num;i++) 31 fin >> a[i]; 32 quicksort(a,0,num-1); 33 for (int i=0;i<num;i++) cout<<a[i]<<' '; 34 return 0; 35 }
快速排序的重点和难点应该在于如何划分数组,这里给出最经常使用的方法:以数组的第一位为标志位。先从末尾找到比标志位小的数A,代表该数应该被放置在标志位以前。而后把标志位当作一个须要数字来填的坑,将A填入坑中,此时A本来的位置变成了一个新坑。而后咱们再从开头寻找比标志位大的数B,代表该数应该被放置在标志位以后。将B填入A本来的坑中,此时B本来的位置成为一个新坑等待下一个A来填。数组
例如咱们用快速排序的思想对下面的数组进行排序:优化
初始状态:ui
5 3 9 6 1 4 2 7 8 标志位为5,因此咱们的目的是把5放在数组中间使得在5以前的数字比5小,在5以后的数字比5大。spa
执行 while(st<ed && a[ed] >= mark) ed--; 得:指针
5 3 9 6 1 4 2 7 8 7,8都大于5, 2是第一个小于5的数字code
执行 if (st<ed) a[st++] = a[ed]; 得:
2 3 9 6 1 4 2 7 8 咱们会在最后将5放到合适的位置,因此没必要担忧5被覆盖,而2虽然还在原来的位置,可是咱们下一次将会用其余数字覆盖它
执行 while(st<ed && a[st] < mark) st++;得:
2 3 9 6 1 4 2 7 8 3小于5,9是第一个大于5的数字
执行 if (st<ed) a[ed--] = a[st]; 得:
2 3 9 6 1 4 9 7 8 ,同理9原来的位置会在下一次被其余数字覆盖(不难看出来是4)
如此循环下去直到两个标志指针碰见,表示数组已经遍历完成。最后,应该剩下一个B的坑位尚未填,最终咱们将标志位填到里面,此时划分数组完成。
因为咱们第一个挖的坑是处于数组首的标志位,因此咱们须要先从末尾找起,若是先从开头找比标志位大的数B,那么这个数B将无地放置。
(若是咱们以最后一个数为标志位,那么咱们将先从开头找比标志位大的数B填入最后一位,而后再找A填入B原来的位置)
划分数组的本质是数字相对位置的交换,使得最终的数组成为前端任意数比后端任意数小的两个分支。对于快速排序的优化能够将标志位设定为中间的某个数字而不是第一个,而后将两个数的位置交换。这样可使得划分的数组先后端长度相近,使算法效率提升。