手撕排序算法---快速排序

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;
}

补充:如果区间过小,可考虑用加入其他算法排序结合快排,可提高效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值