【苏瞳】C语言+三种快速排序+ 三数取中法优化快排

目录

1.挖坑法

2.左右指针法

3.前后指针法

4.快排优化 -- 三数取中法


快速排序毋庸置疑是最快的排序!?要不对不起它这个名字,哈哈。

这里都以升序为例子。

1.挖坑法

一般都是取第一个做pivot,key=arr[pivot],思想就是使key左边都比key小,右边都比key大。

[left,pivot-1]   pivot   [pivot+1,right]

然后再递归分治arr数组中的左边和右边直到只有一个数字。

单趟排序如下图:

整体代码如下,注释详细:

注意循环里面的循环条件不要忘记 bagin < end ,不然可能会越界。

同样 while里面的找小条件要arr[end] >= key ,这里一定要>=否则可能会死循环。

找大同理。

#include<stdio.h>

//快速排序(挖坑法)  O(N*logN) 
//当数组内有序的时候效率最坏 -> O(N^2)  -> 改进(三数取中法)
void QuickSort(int *arr,int left,int right)//闭区间
{
	if(left >= right)//当区间没有值或者只有一个的时候就不用排啦
	{
		return;
	}
	
	int bagin=left,end=right;
	int pivot=bagin;//坑
	int key=arr[bagin]; //关键字
	
	while(bagin < end)
	{
		//1.右边找小的放到左边
		while(bagin < end && arr[end] >= key)//arr[end] >= key 注意这里要>=否则会死循环
		{
			end--;
		}
		//小的放到左边的坑里
		arr[pivot]=arr[end];
		pivot=end;
		//2.左边找大的放到右边
		while(bagin < end && arr[bagin] <= key)
		{
			bagin++;
		}
		//大的放到右边的新坑里
		arr[pivot]=arr[bagin];
		pivot=bagin;
	}
	pivot=bagin;//pivot=end;
	arr[pivot]=key;
	
	//[left,right]
	//[left,pivot-1] pivot [pivot+1,right]
	//如果左 右子区间有序整体就有序了 -> 分治递归
	QuickSort(arr,left,pivot-1);
	QuickSort(arr,pivot+1,right);
}


int main()
{
	int arr[]={5,2,1,4,3,6,9,8,7,0};
    QuickSort(arr,0,10-1);
	for(int i=0;i<10;i++)
	{
		printf("%d ",arr[i]);
	} 
	return 0;
}


2.左右指针法

思想完全和第一种一样,就是这种找比key大或小是用左右两个指针完成的。

整体代码如下,注释详细:

#include<stdio.h>

void Swap(int *a,int *b)
{
	int temp=*a;
	*a=*b;
	*b=temp;
}


//挖坑法(变形) —> 左右指针法(思路一样)
void QuickSort(int *arr,int left,int right)//闭区间
{
	if(left >= right)
	{
		return;
	}
	
	int bagin=left,end=right;//左右指针
	int keyi=bagin;
	
	while(bagin < end)
	{
		while(bagin < end && arr[end] >= arr[keyi])//找小的
		{
			end--;
		}
		
		while(bagin < end && arr[bagin] <= arr[keyi])//找大的
		{
			bagin++;
		}
		
		Swap(&arr[bagin],&arr[end]);
	}
	Swap(&arr[bagin],&arr[keyi]);//这时bagin和end相等而且它们都指向中间 —> Swap(&arr[end],&arr[keyi]);
	
	//[left,bagin-1] [bagin] [bagin+1,right]
	QuickSort(arr,left,bagin-1);
	QuickSort(arr,bagin+1,right);
}


int main()
{
	int arr[]={5,2,1,4,3,6,9,8,7,0};
    QuickSort(arr,0,10-1);
	for(int i=0;i<10;i++)
	{
		printf("%d ",arr[i]);
	} 
	return 0;
}

3.前后指针法

这种实现和上面两种略有不同。

还是取第一个值的下标作keyi,利用前面两个指针 prev cur

cur找小,每次遇到比keyi小的值就停下来,prev++,交换prev和cur位置的值

如下图:

整体代码如下,注释详细:

#include<stdio.h>

void Swap(int *a,int *b)
{
	int temp=*a;
	*a=*b;
	*b=temp;
}


//挖坑法(变形) —> 前后指针法
void QuickSort(int *arr,int left,int right)//闭区间
{
	if(left >= right)
	{
		return;
	}

    int keyi=left; 
    
    int prev=left;//cur找小,每次遇到比keyi小的值就停下来,prev++,交换prev和cur位置的值
    int cur=left+1; 
    
    while(cur <= right)//闭区间
    {
    	if(arr[cur] < arr[keyi] && (++prev)!=cur)//这样加个判断可以防止prev和cur相等时交换,自己和自己交换没意义
    	{
    		Swap(&arr[prev],&arr[cur]);
		}
//		if(arr[cur] < arr[keyi])//这样写也行
//    	{
//    		prev++;
//    		Swap(&arr[prev],&arr[cur]);
//		}
		cur++;
    }
    Swap(&arr[keyi],&arr[prev]);
    
    //[left,prev-1] [prev] [prev+1,right]
	QuickSort(arr,left,prev-1);
	QuickSort(arr,prev+1,right);
}


int main()
{
	int arr[]={5,2,1,4,3,6,9,8,7,0};
    QuickSort(arr,0,10-1);
	for(int i=0;i<10;i++)
	{
		printf("%d ",arr[i]);
	} 
	return 0;
}


4.快排优化 -- 三数取中法

众所周知,快速排序的时间复杂度为O(N*logN)

什么时候最坏呢?

当然是每次取的key恰好是最大值或者最小值,即数组已经有序,这时的时间复杂度就是O(N^2)

大致如下图:

为了避免这种情况可以,让key取尽量中间值即三数取中法。

整体代码如下,注释详细:

下面是对挖坑法优化,其他方法优化一样,调用一下GetMidIndex函数就行了

#include<stdio.h>

void Swap(int *a,int *b)
{
	int temp=*a;
	*a=*b;
	*b=temp;
}

//快速排序 优化 -> (三数取中法)
int GetMidIndex(int *arr,int left,int right)//取中间值下标函数
{
	int mid=(left+right)>>1;//int mid=(left+right)/2;
	if(arr[left] < arr[mid])
	{
		if(arr[mid] < arr[right])// 例如:2(L)  3(mid)   4(R)
		{
			return mid;
		}
		else //arr[mid] > arr[right]  例如:2(L)  4(mid)   3(R)  -> mid已经最大,left right中大的的就是中间值
		{
			if(arr[left] > arr[right])//例如:3(L)  4(mid)   2(R)
			{
				return left;
			}
			else//例如:2(L)  4(mid)   3(R)
			{
				return right;
			}
		}
	}
	else//a[left] > arr[mid]
	{
		if(arr[mid] > arr[right])
		{
			return mid;
		}
		else//arr[mid] < arr[right]  -> mid已经最小,left right中小的的就是中间值
		{
			if(arr[left] < arr[right])
			{
				return left;
			}
			else
			{
				return right;
			}
		}
	}
}


void QuickSort(int *arr,int left,int right)//闭区间
{
	if(left >= right)
	{
		return;
	}
	
	int index=GetMidIndex(arr,left,right);
	Swap(&arr[left],&arr[index]);//交换一下,防止key取到最小值或者最大值
	
	//下面逻辑不变,和挖坑法的一样
	int bagin=left,end=right;
	int pivot=bagin;//坑
	int key=arr[bagin]; //关键字
	
	while(bagin < end)
	{
		//1.右边找小的放到左边
		while(bagin < end && arr[end] >= key)
		{
			end--;
		}
		//小的放到左边的坑里
		arr[pivot]=arr[end];
		pivot=end;
		//2.左边找大的放到右边
		while(bagin < end && arr[bagin] <= key)
		{
			bagin++;
		}
		//大的放到右边的新坑里
		arr[pivot]=arr[bagin];
		pivot=bagin;
	}
	pivot=bagin;//pivot=end;
	arr[pivot]=key;
	
	//[left,right]
	//[left,pivot-1] pivot [pivot+1,right]
	//如果左 右子区间有序整体就有序了 -> 分治递归
	QuickSort(arr,left,pivot-1);
	QuickSort(arr,pivot+1,right);
}


int main()
{
	int arr[]={5,2,1,4,3,6,9,8,7,0};
    QuickSort(arr,0,10-1);
	for(int i=0;i<10;i++)
	{
		printf("%d ",arr[i]);
	} 
	return 0;
}

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
好的,下面是使用C语言,三数来实现快速排序的代码: ``` #include <stdio.h> /* 交换两个数的位置 */ void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } /* 三数枢纽元 */ int median(int arr[], int left, int right) { int center = (left + right) / 2; /* 保证 left <= center <= right */ if (arr[left] > arr[center]) swap(&arr[left], &arr[center]); if (arr[left] > arr[right]) swap(&arr[left], &arr[right]); if (arr[center] > arr[right]) swap(&arr[center], &arr[right]); /* 将 center 放到 right - 1 的位置 */ swap(&arr[center], &arr[right - 1]); /* 返回枢纽元的值 */ return arr[right - 1]; } /* 快速排序 */ void quick_sort(int arr[], int left, int right) { if (left < right) { int i = left, j = right - 1; int pivot = median(arr, left, right); /* 选枢纽元 */ while (1) { /* 从左往右找到第一个大于枢纽元的数 */ while (arr[++i] < pivot) {} /* 从右往左找到第一个小于枢纽元的数 */ while (arr[--j] > pivot) {} if (i < j) { /* 将左边的数与右边的数交换 */ swap(&arr[i], &arr[j]); } else { /* 结束循环 */ break; } } /* 将枢纽元与 i 所在位置的数交换 */ swap(&arr[i], &arr[right - 1]); /* 对左边的子数组进行快速排序 */ quick_sort(arr, left, i - 1); /* 对右边的子数组进行快速排序 */ quick_sort(arr, i + 1, right); } } int main() { int arr[] = {6, 2, 5, 4, 3, 1}; int len = sizeof(arr) / sizeof(arr[0]); quick_sort(arr, 0, len - 1); for (int i = 0; i < len; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; } ``` 在这个实现,我们使用了三数来选枢纽元,这可以有效地避免最坏情况的发生,提高快速排序的效率。此外,我们还实现了一个 `swap` 函数来交换两个数的位置。最后,我们在 `main` 函数定义了一个待排序的数组,并且调用 `quick_sort` 函数对其进行排序
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值