快排
以下是本人的看完下面这一视频后的心得体会,该文章内容大致分为:快排的核心以及视频的快排与408课本上的快排的区别.如果看不懂的地方可以先看下面这位大佬的视频,再回过头来看该文章。若有错误的地方忘各位友友指出!!!🥳🥳🥳
-
思路:本质上通过每次递归选取任意一个元素作为枢轴来进行划分(408以第一个元素作为枢轴),将比枢轴小的元素放到枢轴的左边,大的元素放在枢轴的右边(注意!!!左右元素的顺序无所谓,只关心大的在枢轴的右边,小的在枢轴的左边)。因此,每次递归都能确定一个元素在表中的绝对位置,通过递归每次选取一个元素,每次将该元素放在表中的绝对位置,这样就能达到完全排序的效果。
-
代码分为两部分
- void QuickSort(ElemType A[], int low, int high)——对数组进行排序,即主要作用是对枢轴的左右两边的元素进行排序。
- int Partition(ElemType A[], int low, int high)——对数组随机划分,即主要作用是获取枢轴,并将小于枢轴的元素放枢轴左边,大于枢轴的元素放枢轴右边。
- QuickSort明明只是递归调用自身和Partition,为什么能达到对枢轴左右两边的元素进行排序呢?
Partition并没有对元素进行排序的效果,只能达到划分(左,枢轴,右)的区间效果,但QuickSort函数妙就妙其在每次枢轴的左边和右边调用Partition,每次获取一个元素的绝对位置,获取到枢轴左右两边所有元素的绝对位置,等效于对元素进行排序的效果。
- 递归的过程区间的划分
- 蓝色部分:小于枢轴
- 红色部分:大于枢轴
- 灰色部分:还未比较的元素
- 黄色部分:枢轴
在408大纲里,用int pivot另存枢轴,数组从外向里缩,这就意味着:数组的左半部分对应于上述的蓝色部分(小于枢轴);中部分对应下面的灰色部分(未比较的元素);数组的右半部分对应于上述的红色部分(大于枢轴);pivot对应于黄色部分。
- pivot与i(对应于408的low)位置互换,再返回枢轴的下标位置
-
视频上的代码是这样的:
这个代码思路是直接拿最后一个元素当枢轴,Partition返回的
i
刚好是大于枢轴的第一个元素(右半部分并还未排序),所有Swap不会影响;但如果直接拿第一个元素当枢轴,那么返回的应该是i - 1
//分区:return:枢轴下标。 将小于枢轴的元素放在枢轴左半部,大于放在右半部,无需关系左半部和右半部的排序
int Partition(int A[], int l, int r){
int pivot_index = r; //将表中的最后一个元素认作枢轴
//该行可交换也可不交换
int i = l; //i作为分割线的下标,也就是比右半部分第一个下标
for(int j = l; j < r; j++){
if(A[j] <= A[pivot_index]){ //当元素小于枢轴对应的元素,交换i和j的值,并且i和j一起向前移
Swap(A[i], A[j]);
i++;
}
}
Swap(A[i], A[pivot_index]); //最后将枢轴与i对应的值进行交换
return i; //返回枢轴下标
}
//快排:对枢轴左右元素进行排序
void QuickSort(int A[], int l, int r){
if(l >= r)return; //当表里只有一个元素或者没有元素时,无需排序
int pivot_index = Partition(A, l, r); //获取枢轴下标
QuickSort(A, l, pivot_index - 1); //对枢轴左半部分进行排序
QuickSort(A, pivot_index + 1, r); //对枢轴右半部分进行排序
}
-
408代码是这样的
这个代码思路与上面不同的地方是:其左边是小于枢轴的部分,右边是大于枢轴的部分,中间是未排序的部分,特地用int pivot来保存枢轴;而上面的代码时保存pivot的下标,其左边也是小于枢轴的部分,中间分两部分:一、大于枢轴的部分。二、未排序的部分,最右边第一个是枢轴。
//分区:return:枢轴下标。 将小于枢轴的元素放在枢轴左半部,大于放在右半部,无需关系左半部和右半部的排序
int Partition(int A[], int l, int r){
int pivot = A[l]; //把表中的第一个元素作为枢轴
while(l < r){
while(l < r && A[r] >= pivot)r--; //在右半部分找到比枢轴小的元素
A[l] = A[r]; //将该元素赋值到左边
while(l < r && A[l] <= pivot)l++; //在左半部分找到比枢轴大的元素
A[r] = A[l]; //将该元素赋值到右边
}
A[l] = pivot; //l对应的值刚好是大于pivot的右半部分第一个元素
return l; //返回pivot所在的位置
}
//快排:对枢轴左右元素进行排序
void QuickSort(int A[], int l, int r){
if(l < r){ //表中的元素大于1个才排序
int pivot_index = Partition(A, l, r); //获取pivot所在的位置
QuickSort(A, l, pivot_index - 1); //对pivot左半部分进行排序
QuickSort(A, pivot_index + 1, r); //对pivot右半部分进行排序
}
}