C-语言 快速排序(递归)

#define _CRT_SECURE_NO_WARNINGS
#include<string.h>
#include <stdio.h>
#include<assert.h>
//交换
void swap(int *a,int *b) 
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
//三数取中(时间复杂度可以认为是O(N*logN),几乎不会出现最坏情况,大大减小了递归调用深度,有效提高算法效率;)
int  getmidindex(int *a,int begin, int end)
{
	int mid = (end - begin + 1) / 2;//中间指针
	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
		{
			return mid;
		}
		else if (a[begin] > a[end])
		{

			return begin;
		}
		else
		{
			return  end;
		}
	}
	else//a[begin]>=a[mid]
	{
		if (a[begin]<a[end])
		{
			return begin;
		}

		else if (a[mid]>a[end])
		{
			return mid;

		}
		else
		{
			return end;
		}

	}

}
	
//直接插入排序
void InsertSort(int* a, int sz)
{
	for (int i = 0; i < sz - 1; i++)
	{
		//当i=sz-2时,end也等于sz-2,tmp等于sz-1,代表所有的数都已加入数组,并开始排序最后一个数;
		int end = i;//下标从0开始,代表刚开始数组只有一个数,然后用第二个数与第一个数比较;
		int tmp = a[end + 1];//保留后一位数据;
		//当end指针移动到第一个元素(下标为0),并且该元素小于tmp,end--等于-1,跳出循环后,把tmp(要进行排序的值)放到第一位;
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];//如果要插入的数比a[end]小,就把a[end]往后移一位;
				end--;//索引往前挪一位;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;//直到遇到比tmp小的数,把他刚好放到这个数后面;
	}
}

//hoare
int QuickSort1(int *a,int begin,int end)
{
	//三数取中,把中间的值和第一个值交换,防止有序数组;
	int mid = getmidindex(a, begin, end);
	swap(&a[begin], &a[mid]);

	int left = begin;//左指针
	int right = end;//右指针

	int keyi = left;//选取数组左边第一个数作为基准值,right指针先走,直到找到一个小于基准值的值,或者一把子和left相等;

	//每次定位好一个值;
	while (left < right)
	{
		//找小于key的;
		while (left < right && a[right] >= a[keyi])//left<right防止数组越界,当left=right的时候,指针不再进行移动;带等于号,防止遇和key相等的值,right指针不动了,造成死循环;
		{
			right--;
		}

		//找大于key的;
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}
		//交换大于key的值和小于key的,相当于把小数放到左边,大数放到右边;
		swap(&a[left], &a[right]);
	}
	//当left==right,左右指针相遇,跳出大循环,就交换key和a[left]
	swap(&a[left], &a[keyi]);
	//现在基准值在a[left];
	keyi = left;

	return keyi;
	
}
//挖坑法
int QuickSort2(int* a, int begin, int end)
{
	int left = begin;
	int right = end;

	int key = a[left];//把左边第一个值(基准值)保留到key中;
	int hole = left;//第一个坑;

	while (left<right)
	{
		while(left<right&&a[right]>=key)
		{
			right--;
		}
		a[hole] = a[right];
		hole = right;

		while(left < right && a[left] <= key)
		{
			left++;
		}
		a[hole] = a[left];
		hole = left;
	}
	a[hole] = key;
	return hole;
}

//前后指针法
int QuickSort3(int* a, int begin, int end)
{
	int prev = begin;
	int cur = begin + 1;
	int keyi = begin;
	//单趟
	//前后指针(cur找小)
	while (cur <= end) 
	{
		//防止出现cur到达数组最后一个,明明比a[keyi]大,却仍然进行交换;
		//当a[cur]小于a[keyi],才进行++prev;
		if (a[cur] < a[keyi] && ++prev != cur)//++prev如果等于cur,说明cur指向一个小于a[keyi]的数,但是prev和cur紧邻,相当于自己和自己交换没有必要!
		{
			swap(&a[prev], &a[cur]);  
		}
		cur++;//无论什么情况,cur都得往后走;
	}
	swap(&a[prev], &a[keyi]);//这里的prev一定指向的是小于a[keyi];
	keyi = prev;

	return keyi;//返回一个已经确定好的值的索引;

	
	int prev = begin;
	int cur = begin + 1;

	int keyi = begin;

	while (cur<=end)
	{		
		if (a[cur] < a[keyi]&&++prev!=cur)
			swap(&a[cur],&a[prev]);
		cur++;
	}
	swap(&a[keyi],&a[prev]);
	keyi = prev;

	return keyi;
}
//快速排序(递归)
//1.QuickSort1->hoare法
//2.QuickSort2->挖坑法
//3.QuickSort3->前后指针法
void QuickSort(int *a, int begin,int end)
{
	//递归返回条件;
	if (begin>=end) 		
	 return; 

	//为防止序列有序,每次都找最左边或者最右边(时间复杂度相当于O(n^2))||最后剩余一小部分数并没有必要使用递归(会导致算法复杂度变大很多);
	
	//小区间用直接插入排序,减少递归调用次数;
	if ((end - begin + 1) < 5)
	{
		InsertSort(a+begin, end-begin+1);
	} 

	else 
	{	
		int keyi = QuickSort3(a,begin,end);
		
		//递归调用
		//如果a[left]和a[right]在最左边或者最右边相遇的话,那么将不存在左区间或右区间;
		QuickSort(a, begin, keyi - 1);//左区间

		QuickSort(a, keyi + 1, end);//右区间
	}

}



int main()
{
	int arr[] = {55,77,33,44,22,11,99,77,66,88};
	int sz = sizeof(arr) / sizeof(arr[0]);

	//快速排序;
	int begin = 0;//左指针
	int end = sz - 1;//右指针

	QuickSort(arr,begin,end);
	//打印检测
	for (int i=0;i<sz;i++)
	{
		printf("%d ",arr[i]);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值