快速排序的两种改进方法算法及topK问题求解

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

/**
 * 位操作实现的交换算法
 */
void swap(int *a int *b)
{
	*a = *a^*b;
	*b = *a^*b;
	*a = *a^*b;
}

int my_rand(int low int high)
{
	time_t t;
	srand(time(&t));
	return rand()%(high-low+1)+low;
}

/*
 * 三个数,选择中位数为枢元
 * 调整,将中位数调整到a[low]的位置
 */
void median(int *a int *b int *c)
{
	if(*a<*b)
		swap(a b);
	if(*c<*b)
		swap(cb);
	if(*a>*c)
		swap(ab);
}

int partition(int *a int low int high)
{
	//枢元选择演进
	//1. 直接选取第一个a[low]做为枢元
	//int pivot = a[low];

	//2. 随机选择
	/*swap(&a[low] &a[my_rand(lowhigh)]);
	int pivot = a[low];*/

	//3. 三数中位数法,确定枢元
	median(&a[low] &a[(low+high)/2]&a[high]);
	int pivot = a[low];
//	printf("%d\n" pivot);

	while(low<high)
	{
		while(low<high && a[high]>=pivot) high--;	//下行找到比pivot小数
		a[low] = a[high];
		while(low<high && a[low]<=pivot) low++;
		a[high] = a[low];
	}
	a[low] = pivot;
	return low;
}

void qsort(int *a int low int high)
{
	if(low<high)
	{
		int pos = partition(a low high);
		qsort(a pos+1 high);
		qsort(alow pos-1);
	}
}

/**
 * 引申:用快排来求最小第K个数,时间复杂度为O(n)的解法
 * 凭借最小第k个数,因为通过划分来确定大小区间,因此也解决了TopK的问题,在k之前的数都是比第k个数小的数
 */
int Kmin_qsort(int *a int low int high int k)
{
	if(k<1 || k>high-low+1)	
		return -1;	

	if(low<high)
	{
		int pos = partition(a low high);
		int m = pos - low + 1;
		if(m == k)
			return a[pos]; //如果m=k,说明k位置的元素就是数组中第k小的数
		else if (m > k)
			return Kmin_qsort(a low pos-1 k); //m>k,说明第k小的数,还在pos位置的左边,丢弃右边区间,只在左区间里继续找
		else
			return Kmin_qsort(a pos+1 high k-m); //m<k,说明pos左右是数都是小于第k小的数,因此,第k小的数在右边区间,第k小的数,在右边区间是第k-m小的数。
	}
}

void PrintK(int *a int n)
{
	for(int i=0; i<n; i++)
	{
		printf("%d " a[i]);
	}
	printf("\n");
}

int main()
{
	int a[] = {1,3,5,6,2,0,9,8,7,4};
	int size = sizeof(a)/sizeof(int);
	printf("%d\n" Kmin_qsort(a,0,size-1,3));
	PrintK(a,3);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值