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

堆排序实现以及相关笔试题

2013年10月12日 ⁄ 综合 ⁄ 共 2409字 ⁄ 字号 评论关闭

本博文内容为堆排序的实现,以及堆排序的相关笔试题,如求数组的topk元素,优先队列实现等

1.堆排序的实现

原理:堆排序是基于二叉树实现的,主要步骤为:
先建立二叉堆(堆元素从 n/2 - -  1 执行向上调整操作) (二叉堆分为小根堆与大根堆),再不断执行以下步骤:将根元素与根底元素互换,且将未排序的堆总元素减一,并执行将根顶元素向下调整操作,直到未排序堆总元素为0
具体代码如下:
//////////////////////////////////
// 实现小根堆的相关操作
/////////////////////////////////
bool isLess(int a, int b) { 
	return a<b; 
}

void exch(int &a, int &b) { 
	int temp=a;
	a=b;
	b=temp;
}

//向上调整函数
void shiftup(int *data, int pos){
	while(pos/2>=1)       //pos/2>=1要注意
	{
		if(isLess(data[pos/2], data[pos])) 
			break;
		exch(data[pos/2], data[pos]);
		pos=pos/2;
	}
}
//向下调整函数
void shiftdown(int *data, int pos, int n){
	while(2*pos<=n){		//data[0]代表数组的元素个数,2*pos<=n细节要注意
		int k=2*pos;
		if(k<n && isLess(data[k+1], data[k])) k++;  //k<n要注意
		if(isLess(data[pos], data[k])) break;
		exch(data[pos], data[k]);
		pos=k;
	}
}

//堆排序(降序排序)
void heap_sort(int *data){
	int i=0;
	for(i=data[0]/2; i>=1; i--)
		shiftup(data, i);
	int n = data[0];
	while(n>=1){	//n>=1要注意
		exch(data[1], data[n]);
		shiftdown(data, 1, --n);  //--n要注意	
	}
}

2. 优先队列(根顶元素为最小值)的实现

优先队列的实现原理是利用了二叉堆的性质,一般至少包括2个操作:
插入元素:insert(先判断插入后元素的个数(n+1)是否超过优先队列的最大个数,在将data[++n]=val,并将该元素进行向上调整操作)
返回队列的最小值(或最大值): extractmin(首先判断优先队列中是否有元素(n-1<0),再保存优先队列的首元素,将最后一个元素与第一个元素交换,并将元素个数减一,最后对优先队列首元素执行向下调整操作)
具体代码:
///////////////////////////////////
// 实现优先队列的相关操作
///////////////////////////////////

class prior_queue{
public:
	prior_queue(int m);		//构造函数
	void insert(int val);	//插入元素
	int extractmin();		//取优先队列的最小值
	~prior_queue();			//析构函数
private:
	int *m_data;
	int maxsize;
	int n;
	
private:
	void shiftdown(int pos);	//向下调整
	void shiftup(int pos);		//向上调整
	void exch(int &a, int &b) { int temp=a; a=b; b=temp; }
};

prior_queue::prior_queue(int m){
	m_data = new int[m+1];
	maxsize=m;
	n=0;
}

prior_queue::~prior_queue(){
	delete[] m_data;
}

void prior_queue::shiftdown(int pos){
	while(2*pos<=n){
		int k=2*pos;
		if(k<n && m_data[k+1]<m_data[k]) k++;
		if(m_data[pos]<m_data[k]) break;
		exch(m_data[pos], m_data[k]);
		pos=k;
	}
}

void prior_queue::shiftup(int pos){
	while(pos/2>=1){
		if(m_data[pos/2]<m_data[pos]) break;
		exch(m_data[pos], m_data[pos/2]);
		pos=pos/2;
	}
}

void prior_queue::insert(int val){
	n = n+1;
	if(n>maxsize)	return ;
	m_data[n]=val;
	shiftup(n);
}

int prior_queue::extractmin(){
	if(n-1<0)	return 0;
	int min=m_data[1];
	exch(m_data[1], m_data[n--]);
	shiftdown(1);
	return min;	
}

3.输出数组中的top_max_k元素(或者top_max_k)

实现原理:建立一个k个元素的小根堆,来输出数组中的最大的k和元素(或者大根堆,来输出数组中的最小的k的元素)
先对已知数组前k个元素建立一个k小根堆,再将数组的元素(下标从k+1 - -  n)与小根堆根顶元素比较,大则交换,并执行向下调整操作,直至遍历完数组中的全部元素
具体代码:
void top_max_k(int *data, int k){
	int i=0;
	for(i=k/2; i>=1; i--)
		shiftup(data, i);
	i=k+1;
	while(i<=data[0]){
		if(data[i]>data[1]){
			exch(data[i], data[1]);
			shiftdown(data, 1, k);   //shitdown见堆排序中的shiftdown函数
		}
		i++;
	}
}

抱歉!评论已关闭.