快速排序的实现(时间复杂度在任何情况下都是O(n log n))

快速排序是基于分治策略的一种排序算法。基本思想是:对于给定序列按照以下三个步骤进行

  1. 分解序列:将数组的最右边的元素作为划分元,让比他小的都到他的左边,比他大的都放到他的右边
  2. 递归求解:通过递归调用快速排序,分别对划分出的左半端和有半段进行排序。
  3. 合并:当所有的分段都排好序之后进行合并,最后得到的数组就是排好序的数组。
    基于以上思想,可以实现快速排序算法如下:
void QuickPass(int* ar, int left, int right)
{
	if (left < right)
	{
		int pos = DetermineDivision(ar, left, right);//找到划分元位置
		QuickPass(ar, left, pos - 1);//对划分元左端进行排序
		QuickPass(ar, pos + 1, right);//对划分元右端进行排序
	}
}

划分函数是三种排序的基础

int Partition(int* ar, int left, int right)
{
	assert(ar != nullptr);
	int tmp = ar[left];
	while (left < right)
	{
		while (left < right && ar[right] >= tmp)
		{
			right--;
		}
		if (left < right)
		{
			ar[left] = ar[right];
		}
		while (left < right && ar[left] <= tmp)
		{
			left++;
		}
		if (left < right)
		{
			ar[right] = ar[left];
		}
	}
	ar[left] = tmp;
	return left;
}

快速排序可分为三种方法:传统的快速排序,随机数法快速排序以及中位数法快速排序。三种方法的主要区别在于划分元的选择不同,传统的快速排序不论所给的序列如何,都采用序列的端点元素作为划分元,这么做在序列对称的情况下可以取得比较好的效果,但是当对有序序列进行排序的时候效果就不是特别明显了;随机数法快速排序相较于传统的快速排序,在无序对称的情况下时间复杂度差不多,但是在有序的情况下效果较好,缺点就是随机数法有一定的随机性,在一定的概率下可能会起到适得其反的 作用;想要快速排序的时间复杂度在任何情况下都可以达到O(nlongn),那么最好的方法应该是中位数法快速排序,其采用三位取中法确定划分元,该算法对于有序或者无需的数组都可以起到较好的效果。
下面我们来看看三种算法的具体实现:

传统快速排序(不确定划分直接使用序列端点进行划分) :

#include <stdio.h>
#include<assert.h>
#include <stdlib.h>

#define N 2000

template <class Type>
//模板函数,增强函数的实用性
void Swap(Type& a, Type& b)
{
	Type tmp = a;
	a = b;
	b = tmp;
}

//划分函数
int Partition(int* ar, int left, int right)
{
	assert(ar != nullptr);
	int tmp = ar[left];
	while (left < right)
	{
		while (left < right && ar[right] >= tmp)
		{
			right--;
		}
		if (left < right)
		{
			ar[left] = ar[right];
		}
		while (left < right && ar[left] <= tmp)
		{
			left++;
		}
		if (left < right)
		{
			ar[right] = ar[left];
		}
	}
	ar[left] = tmp;
	return left;
}

//对划分的分段进行递归求解
void QuickPass(int* ar, int left, int right)
{
	if (left < right)
	{
		int pos = Partition(ar, left, right);//找到划分元位置
		QuickPass(ar, left, pos - 1);//对划分元左端进行排序
		QuickPass(ar, pos + 1, right);//对划分元右端进行排序
	}
}

void Quicksort(int* ar, int arsize)
{
	assert(ar != nullptr);
	QuickPass(ar, 0, arsize - 1);
}
void Print(int* ar, int n)
{
	assert(ar != nullptr);
	for (int i = 0; i < n; ++i)
	{
		printf("%5d", ar[i]);
	}
	printf("\n");
}
void Init_ar(int* ar, int n)
{
	for (int i = 0; i < n; ++i)
	{
		ar[i] = rand() % n + 1;
	}
}

int main()
{
	int ar[N] = { 0 };
	Init_ar2(ar, N);
	Print(ar, N);
	Quicksort(ar, N);
	Print(ar, N);
	return 0;
}

随机数法快速排序(在分段中取一个随机数作为划分元):

#include <stdio.h>
#include<assert.h>
#include <stdlib.h>
#include <iostream>
#include <Windows.h>

#define N 2000

template <class Type>
//模板函数,增强函数的实用性
void Swap(Type& a, Type& b)
{
	Type tmp = a;
	a = b;
	b = tmp;
}

//划分函数
int Partition(int* ar, int left, int right)
{
	assert(ar != nullptr);
	int tmp = ar[left];
	while (left < right)
	{
		while (left < right && ar[right] >= tmp)
		{
			right--;
		}
		if (left < right)
		{
			ar[left] = ar[right];
		}
		while (left < right && ar[left] <= tmp)
		{
			left++;
		}
		if (left < right)
		{
			ar[right] = ar[left];
		}
	}
	ar[left] = tmp;
	return left;
}


//随机化法划分函数
int Randpartition(int* ar, int left, int right)
{
	//在所要划分的分段内找到一个随机位置,然后将这个位置的数据和left位置的数据进行交换
	int index = rand() % (right - left) + left;
	Swap(ar[left], ar[index]);
	return Partition(ar, left, right);
}


void QuickPass(int* ar, int left, int right)
{
	if (left < right)
	{
		int pos = Randpartition(ar, left, right);//找到划分元位置
		QuickPass(ar, left, pos - 1);//对划分元左端进行排序
		QuickPass(ar, pos + 1, right);//对划分元右端进行排序
	}
}

void Quicksort(int* ar, int arsize)
{
	assert(ar != nullptr);
	QuickPass(ar, 0, arsize - 1);
}
void Print(int* ar, int n)
{
	assert(ar != nullptr);
	for (int i = 0; i < n; ++i)
	{
		printf("%5d", ar[i]);
	}
	printf("\n");
}
void Init_ar(int* ar, int n)
{
	for (int i = 0; i < n; ++i)
	{
		ar[i] = rand() % n + 1;
	}
}

int main()
{
	int ar[N] = { 0 };
	Init_ar2(ar, N);
	Print(ar, N);
	Quicksort(ar, N);
	Print(ar, N);
	return 0;
}

中位数快速排序(以三位取中法取得划分元对序列进行划分):

#include <stdio.h>
#include<assert.h>
#include <stdlib.h>


#define N 2000

template <class Type>
//模板函数,增强函数的实用性
void Swap(Type& a, Type& b)
{
	Type tmp = a;
	a = b;
	b = tmp;
}

//划分函数
int Partition(int* ar, int left, int right)
{
	assert(ar != nullptr);
	int tmp = ar[left];
	while (left < right)
	{
		while (left < right && ar[right] >= tmp)
		{
			right--;
		}
		if (left < right)
		{
			ar[left] = ar[right];
		}
		while (left < right && ar[left] <= tmp)
		{
			left++;
		}
		if (left < right)
		{
			ar[right] = ar[left];
		}
	}
	ar[left] = tmp;
	return left;
}


int GetMid(int* ar, int left, int right)
{
	assert(ar != nullptr);
	int mid = (right - left) / 2 + left;
	if (ar[left] <= ar[right] && ar[right] <= ar[mid])
	{
		mid = right;
	}
	else if (ar[left] >= ar[right] && ar[left] <= ar[mid])
	{
		mid = left;
	}
	else 
		return mid;
}

//确定划分元,找到数组中的第(k+1)/2大的数,然后与第一位进行交换
int  DetermineDivision(int* ar, int left, int right)
{
	assert(ar != nullptr);
	int pos=GetMid(ar, left, right);
	Swap(ar[left], ar[pos]);
	return Partition(ar, left, right);
}

void QuickPass(int* ar, int left, int right)
{
	if (left < right)
	{
		int pos = DetermineDivision(ar, left, right);//找到划分元位置
		QuickPass(ar, left, pos - 1);//对划分元左端进行排序
		QuickPass(ar, pos + 1, right);//对划分元右端进行排序
	}
}

void Quicksort(int* ar, int arsize)
{
	assert(ar != nullptr);
	QuickPass(ar, 0, arsize - 1);
}
void Print(int* ar, int n)
{
	assert(ar != nullptr);
	for (int i = 0; i < n; ++i)
	{
		printf("%5d", ar[i]);
	}
	printf("\n");
}

void Init_ar2(int* ar, int n)
{
	for (int i = 0; i < n; ++i)
	{
		ar[i] = n - i;
	}
}
int main()
{
	int ar[N] = { 0 };
	Init_ar2(ar, N);
	Print(ar, N);
	Quicksort(ar, N);
	Print(ar, N);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值