一步一步写算法(之堆排序)

原文:一步一步写算法(之堆排序)

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

    堆排序是另外一种常用的递归排序。因为堆排序有着优秀的排序性能,所以在软件设计中也经常使用。堆排序有着属于自己的特殊性质,和二叉平衡树基本是一致的。打一个比方说,处于大堆中的每一个数据都必须满足这样一个特性:

    (1)每一个array[n] 不小于array[2*n]

    (2)每一个array[n]不小于array[2 * n + 1]

    构建这样一个堆只是基础,后面我们需要每次从堆的顶部拿掉一个数据,不断调整堆,直到这个数组变成有序数组为主。所以详细的堆排序算法应该是这样的:

    1)构建大堆,使得堆中的每一个数据都满足上面提到的性质

    2)将堆的第一个数据和堆的最后一个数据进行互换,然后重新调整堆,直到堆重新平衡为止

    3)重复2)的过程,直到整个数组有序。

    上面的描述过程很简单,那么实践操作是怎么样的呢?

    a)对入参进行判断

void heap_sort(int array[], int length)
{
	if(NULL == array || 0 == length)
		return ;

	/* to make sure data starts at number 1 */
	_heap_sort(array-1, length);
}

   
b)构建大堆和调整大堆

void _heap_sort(int array[], int length)
{
	int index = 0;
	int median = 0;
	construct_big_heap(array, length);

	for(index = length; index > 1; index --)
	{
		median = array[1];
		array[1] = array[index];
		array[index] = median;

		reconstruct_heap(array, 1, index-1);
	}
}

   
c)构建大堆的细节操作部分

void set_sorted_value(int array[], int length)
{
	int index = length;
	int median = 0;
	if(length == 1) return;

	while(index > 1){
		if(array[index >> 1] >= array[index])
			break;

		median = array[index];
		array[index] = array[index >> 1];
		array[index >> 1] = median;
		index >>= 1;
	}
}

void construct_big_heap(int array[], int length)
{
	int index = 0 ;

	for(index = 1; index <= length; index ++)
	{
		set_sorted_value(array, index);
	}
}

    d)大堆迭代调整

void reconstruct_heap(int array[], int index, int length)
{
	int swap = 0;
	if(length < index << 1)
		return;

	if(length == index << 1){
		adjust_leaf_position(array, index);
		return;
	}

	if(-1 != (swap = adjust_normal_position(array, index))){
		reconstruct_heap(array, swap, length);
	}
}

    e)对单分支节点和满分支节点分别处理

int adjust_normal_position(int array[], int index)
{
	int left = index << 1 ;
	int right = left + 1;
	int median = 0;
	int swap = 0;

	if(array[index] >= array[left]){
		if(array[index] >= array[right]){
			return -1;
		}else{
			swap = right;
		}
	}else{
		if(array[index] >= array[right]){
			swap = left;
		}else{
			swap = array[left] > array[right] ? left : right;
		}
	}

	if(swap == left) {
		median = array[index];
		array[index] = array[left];
		array[left] = median;
	}else{
		median = array[index];
		array[index] = array[right];
		array[right] = median;
	}

	return swap;
}

STATUS adjust_leaf_position(int array[], int index)
{
	int median = 0;
	if(array[index] > array[index << 1])
		return TRUE;

	median = array[index];
	array[index] = array[index << 1];
	array[index << 1] = median;
	return FALSE;
}

   
f)堆排序算法介绍完毕,创建测试用例验证

static void test1()
{
	int array[] = {1};
	heap_sort(array, sizeof(array)/sizeof(int));
}

static void test2()
{
	int array[] = {2, 1};
	heap_sort(array, sizeof(array)/sizeof(int));
	assert(1 == array[0]);
	assert(2 == array[1]);
}

static void test3()
{
	int array[] = {3, 2, 1};
	heap_sort(array, sizeof(array)/sizeof(int));
	assert(1 == array[0]);
	assert(2 == array[1]);
	assert(3 == array[2]);
}

static void test4()
{
	int array[] = {2, 3, 1};
	heap_sort(array, sizeof(array)/sizeof(int));
	assert(1 == array[0]);
	assert(2 == array[1]);
	assert(3 == array[2]);
}

static void test5()
{
	int array[] = {5,3, 4, 1};
	heap_sort(array, sizeof(array)/sizeof(int));
	assert(1 == array[0]);
	assert(3 == array[1]);
	assert(4 == array[2]);
	assert(5 == array[3]);
}

static void test6()
{
	int array[] = {2, 3,6, 8, 7};
	heap_sort(array, sizeof(array)/sizeof(int));
	assert(2 == array[0]);
	assert(3 == array[1]);
	assert(6 == array[2]);
	assert(7 == array[3]);
	assert(8 == array[4]);
}

static void test7()
{
	int array[] = {3,4,2,7,1,9,8,6,5};
	heap_sort(array, sizeof(array)/sizeof(int));
	assert(1 == array[0]);
	assert(2 == array[1]);
	assert(3 == array[2]);
	assert(4 == array[3]);
	assert(5 == array[4]);
	assert(6 == array[5]);
	assert(7 == array[6]);
	assert(8 == array[7]);
	assert(9 == array[8]);
}

【预告: 下面的博客介绍一些常用的数据结构】

时间: 2025-01-28 08:05:10

一步一步写算法(之堆排序)的相关文章

一步一步写算法(之非递归排序)

原文:一步一步写算法(之非递归排序) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]        在上面一篇博客当中,我们发现普通查找和排序查找的性能差别很大.作为一个100万的数据,如果使用普通的查找方法,那么每一个数据查找平均下来就要几十万次,那么二分法的查找呢,20多次就可以搞定.这中间的差别是非常明显的.既然排序有这么好的效果,那么这篇博客中,我们就对排序算做一个总结.     按照我个人的理解,排序可以分为两种:一种是非递归排

一步一步写算法(之 算法总结)

原文:一步一步写算法(之 算法总结) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]       自10月初编写算法系列的博客以来,陆陆续续以来写了几十篇.按照计划,还有三个部分的内容没有介绍,主要是(Dijkstra算法.二叉平衡树.红黑树).这部分会在后面的博客补充完整.这里主要是做一个总结,有兴趣的朋友可以好好看看,欢迎大家提出宝贵意见.       (1) 排序算法     快速排序           合并排序     堆排序

一步一步写算法(之链表排序)

原文:一步一步写算法(之链表排序) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]     相比较线性表的排序而言,链表排序的内容稍微麻烦一点.一方面,你要考虑数据插入的步骤:另外一方面你也要对指针有所顾虑.要是有一步的内容错了,那么操作系统会马上给你弹出一个exception.就链表的特殊性而言,适合于链表的排序有哪些呢?     (1)插入排序    (适合)     (2)冒泡排序    (适合)     (3)希尔排序    (适

一步一步写算法(之挑选最大的n个数)

原文:一步一步写算法(之挑选最大的n个数) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]     从一堆数据中挑选n个最大的数,这个问题是网上流传的比较广的几个问题之一.具体来说,它的意思就是:假设我们有100个数据,我们需要挑选出最大的n个数据(n < 100),那么有没有办法实现这样一个目标呢?在这里,我想从排序的角度看看有没有什么办法可以实现这样一个目标.     在前面的博客当中,我们实现的排序算法有下面几种:     (1)

一步一步写算法(之合并排序)

原文:一步一步写算法(之合并排序) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]     前面一篇博客提到的快速排序是排序算法中的一种经典算法.和快速排序一样,合并排序是另外一种经常使用的排序算法.那么合并排序算法有什么不同呢?关键之处就体现在这个合并上面.     合并算法的基本步骤如下所示:     1)把0~length-1的数组分成左数组和右数组     2)对左数组和右数组进行迭代排序     3)将左数组和右数组进行合并,那

一步一步写算法(之二叉树深度遍历)

原文:一步一步写算法(之二叉树深度遍历) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]     深度遍历是软件开发中经常遇到的遍历方法.常用的遍历方法主要有下面三种:(1)前序遍历:(2)中序遍历:(3)后序遍历.按照递归的方法,这三种遍历的方法其实都不困难,前序遍历就是根-左-右,中序遍历就是左-根-右,后续遍历就是左-右-根.代码实现起来也不复杂.     1)前序遍历 void preorder_traverse(TREE_NOD

一步一步写算法(之克鲁斯卡尔算法 下)

原文:一步一步写算法(之克鲁斯卡尔算法 下) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]     前面在讨论克鲁斯卡尔的算法的时候,我们分析了算法的基本过程.基本数据结构和算法中需要解决的三个问题(排序.判断.合并).今天,我们继续完成剩下部分的内容.合并函数中,我们调用了两个基本函数,find_tree_by_index和delete_mini_tree_from_group,下面给出详细的计算过程. MINI_GENERATE_T

一步一步写算法(之线性结构的处理)

原文:一步一步写算法(之线性结构的处理) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]     我们知道,在内存中的空间都是连续的.也就是说,0x00000001下面的地址必然是0x00000002.所以,空间上是不会出现地址的突变的.那什么数据结构类型是连续内部空间呢,其实就是数组,当然也可以是堆.数组有很多优势,它可以在一段连续空间内保存相同类型的数据,并且对这些数据进行管理.所以从这个意义上说,掌握了数组才能说明你数据结构入门了.

一步一步写算法(之排序二叉树线索化)

原文:一步一步写算法(之排序二叉树线索化) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]     前面我们谈到了排序二叉树,还没有熟悉的同学可以看一下这个,二叉树基本操作.二叉树插入.二叉树删除1.删除2.删除3.但是排序二叉树也不是没有缺点,比如说,如果我们想在排序二叉树中删除一段数据的节点怎么办呢?按照现在的结构,我们只能一个一个数据查找验证,首先看看在不在排序二叉树中,如果在那么删除:如果没有这个数据,那么继续查找.那么有没有方法