基本思想
快速排序是对冒泡排序的一种改进
基本思想:
- 通过一趟排序将要排序的数据分割成独立的两部分。
- 其中一部分的所有数据都比另外一部分的所有数据都要小。
- 然后再按此方法对这两部分数据分别进行快速排序,整个排序可以递归进行,一次整个数据变成有序序列
注意:
其主要运用了分治的思想
有不同种方法将该段数据分成两段(小于等于key的一段在一边,大于key的一段在一边,key的数据在这两段段中间)
快排一次只能把一个数排好,放在正确的位置。
key可以选最左边的数,此时先移动右边的数j,
key也可以选最右边的数,此时先移动左边的数i
快速排序主要有两种方法,一种是标准算法,另一种是两头交换法,基本思想是一样的,但有些细节上有所不同。
方法一:两头交换法
过程图解:
首先我们选取最左边的数为标准数key,再设最左边的数为i,设最右边的数为j.注意此时从右边开始移动。
key = 6
j从右向左移动直到找到比key小的那个数停下
i从左往右移动直到找到比key大的数停下。
交换它们两个。
即6 1 2 5 9 3 4 7 10 8
i | j | ||||||||
---|---|---|---|---|---|---|---|---|---|
6 | 1 | 2 | 5 | 9 | 3 | 4 | 7 | 10 | 8 |
key = 6
继续进行上面的操作,
j从右向左移动直到找到比key小的那个数停下
i从左往右移动直到找到比key大的数停下。
然后交换它们两个。
6 1 2 5 4 3 9 7 10 8
i | j | ||||||||
---|---|---|---|---|---|---|---|---|---|
6 | 1 | 2 | 5 | 4 | 3 | 9 | 7 | 10 | 8 |
最终j找到比key小的数停下
i继续向前寻找时与j相遇。
此时交换这个数与key的位置。
即3 1 2 5 4 6 9 7 10 8
可以看出来key此时所处的位置,前面都是比key小的,后面都是比key大的。所以这里就是key的位置
然后分别对6前半段和后半段进行上面的排列
最终排序完成。
代码实现:
int a[100];
void quicksort(int left, int right);
int main() {
int n;
scanf("%d",&n);
for(int i = 0; i < n; i++) {
scanf("%d ",&a[i]);
}
quicksort(0, n-1);
for(int i = 0; i < n; i++) {
printf("%d ",a[i]);
}
return 0;
}
void quicksort(int left, int right) {
int i, j, t;
if(left > right) {
return ;
}
int key = a[left];
i = left;
j = right;
while ( i != j) {
while (a[j] >= key && i < j) {
j--;
}
while (a[i] <= key && i < j) {
i++;
}
if(i < j) {
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
a[left] = a[i];
a[i] = key;
quicksort(left, i-1);
quicksort(i+1, right);
}
方法二:标准算法(填坑法)
优化不必要的交换,直接进行替换操作,不进行交换。
key=23
第一步,i=0, j=8.选取基准数key为23.
可以想象成i = 0那个位置有一个坑,标记为*
j开始向左移动。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
23 | 15 | 37 | 89 | 2 | 21 | 43 | 9 | 56 |
i=0 | <-- j=8 | |||||||
* |
第二步:
从j向左寻找比key小的数,找到后填入坑中,此时j所在的位置就变成坑了。
i开始向右移动
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
9 | 15 | 37 | 89 | 2 | 21 | 43 | 9 | 56 |
i=0 --> | j=7 | |||||||
* |
下一步:
i从左往右移动,寻找比key大的数,找到后填入坑中,并且i此时所在的位置就变成了坑。
j开始向右移动。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
9 | 15 | 37 | 89 | 2 | 21 | 43 | 37 | 56 |
i=2 | <-- j=7 | |||||||
* |
下一步:
j从右往左移动,寻找比key小的数,找到后填入坑中,并且j此时所在的位置就变成了坑。
i开始向右移动。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
9 | 15 | 21 | 89 | 2 | 21 | 43 | 37 | 56 |
i=2 --> | j=5 | |||||||
* |
下一步:
i从左往右移动,寻找比key大的数,找到后填入坑中,并且i此时所在的位置就变成了坑。
j开始向左移动。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
9 | 15 | 21 | 89 | 2 | 89 | 43 | 37 | 56 |
i=3 | <-- j=5 | |||||||
* |
下一步:
j从右往左移动,寻找比key小的数,找到后填入坑中,并且j此时所在的位置就变成了坑。
i开始向左移动。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
9 | 15 | 21 | 2 | 2 | 89 | 43 | 37 | 56 |
i=3 --> | j=4 | |||||||
* |
i向右移动,此时与j相遇 i = j = 4.
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
9 | 15 | 21 | 2 | 2 | 89 | 43 | 37 | 56 |
i = j=4 | ||||||||
* |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
9 | 15 | 21 | 2 | 23 | 89 | 43 | 37 | 56 |
key | ||||||||
* |
此时key 23所在的位置就是它在排列中应该在的位置。前面的数都是比他小的数,后面都是比它大的数。
最后我们对以上的操作进行分治,即分别对23前面的数列和后面的数列进行上面的操作排序。
最终排序完成。
代码实现:
#include<stdio.h>
int a[100];
void quicksort(int a[], int low, int high) {
int i = low;
int j = high;
int key = a[low];
while (i < j) {
while (i < j && a[j] >= key) {
j--;
}
if( i < j) {
a[i] = a[j];
}
while (i < j && a[i] < key) {
i++;
}
if( i < j) {
a[j] = a[i];
}
}
a[i] = key;
if(low < i) quicksort(a, low, i-1);
if(high >i) quicksort(a, i+1, high);
}
int main() {
int n;
scanf("%d",&n);
for(int i = 0; i < n; i++) {
scanf("%d ",&a[i]);
}
quicksort(a, 0, n-1);
for(int i = 0; i < n; i++) {
printf("%d ",a[i]);
}
return 0;
}