现在的位置: 首页 > 综合 > 正文

编程艺术第三章 找最小的K个数

2015年07月23日 ⁄ 综合 ⁄ 共 2230字 ⁄ 字号 评论关闭

原题及解答出处http://blog.csdn.net/v_JULY_v/article/details/6370650

快速排序确定枢轴量的方法,确定了第K个枢轴量,那么继续递归之前的数组区间,就可以得到一个有序的K个数

推荐 http://www.cnblogs.com/morewindows/archive/2011/08/13/2137415.html 介绍的挖坑填数的解释

如果要选择一个特定的数作为枢轴量,只要将这个数与第一个数进行交换,那么这个算法仍然适用!

<pre name="code" class="cpp">// FindK.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "stdio.h"
#define K 3       //前4个最小的数
int array[7] = {8,10,2,4,3,6,10};

void swap(int &a, int &b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
/*void partion(int left, int right)
{

	if (left < right)
	{
		int mid = (left+right)/2;
		int pivot = array[mid];
		int i = left;
		int j = right;
		while(i < j)
		{
			while(array[i] < pivot)       //当A[i] = A[j]时会出现死循环
				i++;
			while(array[j] > pivot)       
				j--;
			
			if (i < j)  //i > j说明越过了枢轴量,不用进行交换了
				swap(array[i], array[j]);
		}
		
		
		
		partion(left, i-1);
		if (i == K-1)
		return;
		partion(i+1, right);
	}
	
}

void partion(int left, int right)
{
	
	if (left <= right)
	{
	
		int pivot = array[(left+right) / 2];
		int i = left;
		int j = right;
		while(i < j)
		{
			while(array[i] < pivot)i++;      
			
			while(array[j] > pivot)j--;       
			
			
			if (i < j)  //i > j说明越过了枢轴量,不用进行交换了
				swap(array[i], array[j]);
			
			if(array[i] ==	array[j]) //完全是为了避免死循环
				j--;

		} 
		
	
		
		partion(left, i-1);
		//if (i == K-1)
		//return;
		partion(i+1, right);
	}
	
}*/

void partion(int left, int right)   //填坑补数法!!
{
	
	if (left <= right)
	{
		
		int pivot = array[left];//将第一个数存至局部枢轴量中,这样第一个数就可以空出来
		int i = left;
		int j = right;
		while(i != j)
		{

			while(i < j && array[j] > pivot)j--;       

			if (i < j)
			{
				array[i] = array[j];    //用j填i的坑,j是新坑
				i++;
			}
			
			while(i < j && array[i] < pivot)i++;      
			
			
			if (i < j)
			{
				array[j] = array[i];    //用i填j的坑,i是新坑
				j--;
			}
			
	
		} 
		
		array[i] = pivot;  //填i的坑
		if (i == K-1)
		return;
		partion(left, i-1);   //i的位置才是枢轴量后的位置
	
		partion(i+1, right);
	}
	
}

int main(int argc, char* argv[])
{

	partion(0, 6);

	
	printf("%d", array[K-1]);

	return 0;
}


方法二:堆排序,出堆K次即可,其中挖坑填数法再次出现,并且要注意下降的时候,选择的是子节点中的最小值进行交换。这一点要牢记

// FindK.cpp : Defines the entry point for the console application.
//


#include "stdafx.h"
#include "stdio.h"
#define K 3       //前4个最小的数
int array[8] = {0,8,10,2,3,3,6,10};


void swap(int &a, int &b)
{
	int tmp = a;
	a = b;
	b = tmp;
}






void SiftDown(int low, int high)
{
	int i = low;
	int j = 2*i;
	int tmp = array[i];
	while(j <= high)
	{
		if (j < high && array[j] > array[j+1]) //选择子孩子中最小的节点
			j++;


		if (tmp > array[j])
		{
			//swap(array[i], array[j]);  
			array[i] = array[j];      //利用好i这个坑,可以再每次循环中减少两次赋值操作,这样j成为新坑
			i = j;					  //因为i = j,所以最后填坑的时候要填array[i]
			j = i * 2;
		}
		else
			break;
		
	}


	array[i] = tmp;
}
void HeapSort(int n)
{
	int i;
	for (i = n/2; i >= 1; i--)
		SiftDown(i, n);
	for (i = n; i > n - K; i--)
	{
		printf("%d", array[1]);
		swap(array[1], array[i]);
		SiftDown(1, i-1);
	}
}
int main(int argc, char* argv[])
{
	HeapSort(7);
		
	return 0;
}

抱歉!评论已关闭.