1.快速排序:
定义:快速排序采用的是分治思想,即在一个无序的序列中选取一个任意的基准元素pit(坑位),利用pivot将待排序的序列分成两部分,前面部分元素均小于或等于基准元素,后面部分均大于或等于基准元素,然后采用递归的方法分别对前后两部分重复上述操作,直到将无序序列排列成有序序列。
思想:分治思想
1.2快速排序(挖坑法)
1.2.1图解分析
1.先随机创建一组数据
2.创建两个前后指针(begin)(end),坑位(pit),关键字 (key)
3.关键思想:(1)右边找到比关键字小的放在左边,左边找比关键字大的放在右边
(2)循环进行,找到放关键字的坑位
(3)使得关键字左边的数都小于关键字,右边的都大于关键字
图示:
先进行右边找大的操作
执行完一次后将新坑位移动到 end位置处,接下来执行左边找比关键字(key)大的操作
代码解析 :
while (begin < end && arr[end] >= key) {
end--;
}
//将比key小的放在前面
arr[pit] = arr[end];
//将end处立为新坑位,为左边找大填补准备
pit = end;
图示:
代码解释:
while (begin < end && arr[begin] <= key) {
begin++;
}
//将比key大的放在后面
arr[pit] = arr[begin];
//将begin处立为新坑位,为右边找小填补准备
pit = begin;
当begin与end重合时 ,说明找到了填写关键字的坑位
1.2.2 分治排序
返回坑的位置,将坑的左右分别进行快速排序,重复上述操作。
int QuickSort1(int* arr, int left, int right) {
if (left >= right) {
return;
}
int begin = left, end = right;//始末指针
//坑位
int pit = begin;
//关键字
int key = arr[begin];
while (begin < end) {
while (begin < end && arr[end] >= key) {
end--;
}
//将比key小的放在前面
arr[pit] = arr[end];
//将end处立为新坑位,为左边找大填补准备
pit = end;
while (begin < end && arr[begin] <= key) {
begin++;
}
//将比key大的放在后面
arr[pit] = arr[begin];
//将begin处立为新坑位,为右边找小填补准备
pit = begin;
}
//找到坑位
pit = begin;
//将关键字加入坑内
arr[pit] = key;
//返回坑位
return pit;
}
将坑位下标作为函数值返回 ,分别进行重复排序操作
int QuickSort(int* arr, int left,int right) {
int Index = QuickSort1(arr, left, right);
//左边排序
QuickSort1(arr, left, Index);
//右边排序
QuickSort1(arr, Index+1, right);
}
2. 提高效率
三数取中:将数据的起始位置,末位置,中间位置数据进行比较大小,选取中间值的数作为关键字。默认将关键字的值放在最左边(数据起始位置/left).
代码:
int ChangeData(int* arr, int left, int right) {
int mid = (left + right) >> 1;
if (arr[mid] > arr[left]) {
if (arr[mid] < arr[right]) {
return mid;
}
else if (arr[right] > arr[left]) {
return right;
}
else {
return left;
}
}
else {//arr[left]>arr[mid]
if (arr[mid] > arr[right]) {
return mid;
}
else if (arr[left] > arr[right]) {
return right;
}
else {
return left;
}
}
}
2.1因此挖坑法完整代码
int QuickSort1(int* arr, int left, int right) {
if (left >= right) {
return;
}
int Index = ChangeData(arr, left, right);
Swap(&arr[Index], &arr[left]);
int begin = left, end = right;//始末指针
//坑位
int pit = begin;
//关键字
int key = arr[begin];
while (begin < end) {
while (begin < end && arr[end] >= key) {
end--;
}
//将比key小的放在前面
arr[pit] = arr[end];
//将end处立为新坑位,为左边找大填补准备
pit = end;
while (begin < end && arr[begin] <= key) {
begin++;
}
//将比key大的放在后面
arr[pit] = arr[begin];
//将begin处立为新坑位,为右边找小填补准备
pit = begin;
}
//找到坑位
pit = begin;
//将关键字加入坑内
arr[pit] = key;
//返回坑位
return pit;
}
程序完整代码
#include<stdio.h>
void PrintArry(int* arr, int n) {
for (int i = 0; i < n; i++) {
printf("%d ",arr[i]);
}
}
int ChangeData(int* arr, int left, int right) {
int mid = (left + right) >> 1;
if (arr[mid] > arr[left]) {
if (arr[mid] < arr[right]) {
return mid;
}
else if (arr[right] > arr[left]) {
return right;
}
else {
return left;
}
}
else {//arr[left]>arr[mid]
if (arr[mid] > arr[right]) {
return mid;
}
else if (arr[left] > arr[right]) {
return right;
}
else {
return left;
}
}
}
void Swap(int* p1, int* p2) {
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
//挖坑法
int QuickSort1(int* arr, int left, int right) {
if (left >= right) {
return;
}
int Index = ChangeData(arr, left, right);
Swap(&arr[Index], &arr[left]);
int begin = left, end = right;//始末指针
//坑位
int pit = begin;
//关键字
int key = arr[begin];
while (begin < end) {
while (begin < end && arr[end] >= key) {
end--;
}
//将比key小的放在前面
arr[pit] = arr[end];
//将end处立为新坑位,为左边找大填补准备
pit = end;
while (begin < end && arr[begin] <= key) {
begin++;
}
//将比key大的放在后面
arr[pit] = arr[begin];
//将begin处立为新坑位,为右边找小填补准备
pit = begin;
}
//找到坑位
pit = begin;
//将关键字加入坑内
arr[pit] = key;
//返回坑位
return pit;
}
int QuickSort(int* arr, int left,int right) {
if (left >= right) {
return;
}
int Index = QuickSort1(arr, left, right);
//左边排序
QuickSort1(arr, left, Index-1);
//右边排序
QuickSort1(arr, Index+1, right);
}
3.快速排序(双向指针法)
3,1双向指针法:
思路和挖坑法差不多,但比挖坑法更便捷一些,左边找到比关键字大的,右边找到比关键字的小的,然后将这两处的数值进行一个交换,重复上述操作,直到前后指针相遇,就找的了放关键字的具体坑位,将关键字放入,将坑位下标作为函数值返回,其他操作和挖坑法相同。
3.2图示
创建数组
创建begin指针,end指针,和关键字(key)指针
当每次左右循环满足条件时,将左右值进行交换(Swap(&begin,&end));
一直到begin与end重合停止交换
返回坑位begin ,将区间以此一分为二,重复上述操作。
最终得到
3.3代码如下
#include<stdio.h>
void PrintArry(int* arr, int n) {
for (int i = 0; i < n; i++) {
printf("%d ",arr[i]);
}
printf("\n");
}
int ChangeData(int* arr, int left, int right) {
int mid = (left + right) >> 1;
if (arr[mid] > arr[left]) {
if (arr[mid] < arr[right]) {
return mid;
}
else if (arr[right] > arr[left]) {
return right;
}
else {
return left;
}
}
else {//arr[left]>arr[mid]
if (arr[mid] > arr[right]) {
return mid;
}
else if (arr[left] > arr[right]) {
return right;
}
else {
return left;
}
}
}
void Swap(int* p1, int* p2) {
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int QuickSort2(int* arr, int left, int right) {
//三数取中
int Index= ChangeData(arr, left, right);
//使中间值放在最左边
Swap(&arr[left], &arr[Index]);
int begin = left, end = right;
int key = begin;
while (begin < end) {
//右边找到比关键字小的
while (begin < end && arr[end] >= arr[key]) {
end--;
}
//左边找到比关键字大的
while (begin < end && arr[begin] <= arr[key]) {
begin++;
}
//交换左右值,最终使关键字前面的数据小于关键字,后面的大于关键字
Swap(&arr[end], &arr[begin]);
}
//将关键字移动到合适坑位
Swap(&arr[key], &arr[begin]);
return begin;
}
void QuickSort(int* arr, int left,int right) {
if (left >= right) {
return;
}
/*int Index = QuickSort1(arr, left, right);*/
int Index = QuickSort2(arr, left, right);
//左边排序
QuickSort(arr, left, Index-1);
//右边排序
QuickSort(arr, Index + 1, right);
}
void text01() {
int arr[] = { 4,5,6,9,7,2,3,8 };
QuickSort(arr,0, sizeof(arr) / sizeof(int)-1);
PrintArry(arr, sizeof(arr) / sizeof(int));
}
int main() {
text01();
return 0;
}
4.快速排序(前后指针法)
4.1前后指针法:
思想:分治排序思想,创建快慢指针,和关键字,利用快指针将小于关键字的数据存储到慢指针中,当遍历停止时,便找到了放关键字的坑位。
4.2图解分析
创建数组:
创建慢指针(prev),快指针(cur),和关键字指针(key).
进行一次排序
进行交换操作
左右区间分别进行排序
最终结果
4.3 代码如下
#include<stdio.h>
void PrintArry(int* arr, int n) {
for (int i = 0; i < n; i++) {
printf("%d ",arr[i]);
}
printf("\n");
}
int ChangeData(int* arr, int left, int right) {
int mid = (left + right) >> 1;
if (arr[mid] > arr[left]) {
if (arr[mid] < arr[right]) {
return mid;
}
else if (arr[right] > arr[left]) {
return right;
}
else {
return left;
}
}
else {//arr[left]>arr[mid]
if (arr[mid] > arr[right]) {
return mid;
}
else if (arr[left] > arr[right]) {
return right;
}
else {
return left;
}
}
}
void Swap(int* p1, int* p2) {
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int QuickSort3(int* arr, int left, int right) {
int Index = ChangeData(arr, left, right);
//使中间值放在最左边
Swap(&arr[left], &arr[Index]);
//创立快慢指针
int pur = left, cur = left + 1;
int key = pur;
while (cur <= right) {
//快指针的数据小于关键字数据的点与慢指针交换
if (arr[cur] < arr[key] && ++pur != cur) {
Swap(&arr[cur], &arr[pur]);
}
cur++;
}
//找到坑位,将关键字放入坑位
Swap(&arr[key], &arr[pur]);
//返回坑位
return pur;
}
void QuickSort(int* arr, int left,int right) {
if (left >= right) {
return;
}
//前后指针法
int Index = QuickSort3(arr, left, right);
//左边排序
QuickSort(arr, left, Index-1);
//右边排序
QuickSort(arr, Index + 1, right);
}
void text01() {
int arr[] = { 4,5,6,9,7,2,3,8 };
QuickSort(arr,0, sizeof(arr) / sizeof(int)-1);
PrintArry(arr, sizeof(arr) / sizeof(int));
}
int main() {
text01();
return 0;
}
补充:如果区间过小,可考虑用加入其他算法排序结合快排,可提高效率。