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

简单选择排序-树形选择排序-堆排序

2013年09月16日 ⁄ 综合 ⁄ 共 3300字 ⁄ 字号 评论关闭
/*
功能,数据结构C语言版,P277-P282,简单选择排序-树形选择排序-堆排序
日期,2012年10月30日 星期二
博客,http://blog.csdn.net/shunqiziranhao007/article/details/7821081
环境,win7-32-vs2010
*/
#include <stdio.h>
#include <malloc.h>
#include <math.h>
#include <limits.h>

// 记录类型
typedef struct
{
	int key;		// 关键字项
	int otherinfo;	// 其它数据项
}RedType;

// 一个用作示例的小顺序表的最大长度
#define MAXSIZE 30

// 顺序表类型
typedef struct
{
	RedType r[MAXSIZE+1];	// r[0]闲置或用作哨兵单元
	int length;				// 顺序表长度
}SqList;

// 打印顺序表
void print(SqList L)
{
	int i;
	
	for(i = 1; i <= L.length; i++)
		printf("(%d, %d) ", L.r[i].key, L.r[i].otherinfo);
	
	printf("\n\n");
}

// 返回在L.r[i..L.length]中key最小的记录的序号
int SelectMinKey(SqList L, int i)
{
	int min;
	int j, k;
	
	// 设第i个为最小
	k = i;
	min = L.r[i].key;
	for(j = i+1; j <= L.length; j++)
	{
		if(L.r[j].key < min)
		{
			// 找到更小的
			k = j;
			min = L.r[j].key;
		}
	}

	return k;
}

// 算法10.9
// 对顺序表L作简单选择排序。
void SelectSort(SqList *L)
{
	int i,j;
	RedType t;
	
	for(i = 1; i < (*L).length; ++i)
	{
		j = SelectMinKey(*L, i);
		if(i != j)
		{
			// 与第i个记录交换
			t = (*L).r[i];
			(*L).r[i] = (*L).r[j];
			(*L).r[j] = t;
		}
	}
}

// 树形选择排序 P278
void TreeSort(SqList *L)
{
	int i, j, j1, k, k1, l;
	int n = (*L).length;
	RedType *t;
	
	// 完全二叉树的层数
	l = (int)ceil( log(n) / log(2) ) + 1;
	// l层完全二叉树的结点总数
	k = (int)pow(2, l) - 1;
	// l-1层完全二叉树的结点总数
	k1 = (int)pow(2, l-1) - 1;
	
	// 二叉树采用顺序存储结构
	t = (RedType*)malloc(k * sizeof(RedType));

	// 将L.r赋给叶子结点
	for(i = 1; i <= n; i++)
		t[k1+i-1] = (*L).r[i];
	
	// 给多余的叶子的关键字赋无穷大
	for(i = k1+n; i < k; i++)
		t[i].key = INT_MAX;
	
	j1 = k1;
	j = k;
	while(j1)
	{
		// 给非叶子结点赋值
		for(i=j1;i<j;i+=2)
		{
			t[i].key < t[i+1].key ? ( t[(i+1)/2-1] = t[i] ) :
				( t[(i+1)/2-1] = t[i+1] );
		}
		j = j1;
		j1 = (j1-1)/2;
	}

	for(i = 0; i < n; i++)
	{
		// 将当前最小值赋给L.r[i]
		(*L).r[i+1] = t[0];
		j1 = 0;
		// 沿树根找结点t[0]在叶子中的序号j1
		for(j = 1; j < l; j++)
		{
			t[2*j1+1].key == t[j1].key ?
				(j1 = 2*j1+1) : (j1 = 2*j1+2);
		}
		t[j1].key = INT_MAX;
	
		while(j1)
		{
			// 序号为j1的结点的双亲结点序号
			j1 = (j1+1)/2 - 1;
			
			t[2*j1+1].key <= t[2*j1+2].key 
				? (t[j1] = t[2*j1+1]) : (t[j1] = t[2*j1+2]);
		}
	}
	free(t);
}

// 堆采用顺序表存储表示
typedef SqList HeapType;

// 算法10.10  P282
// 已知H.r[s..m]中记录的关键字除H.r[s].key之外均满足堆的定义,本函数
// 调整H.r[s]的关键字,使H.r[s..m]成为一个大顶堆(对其中记录的关键字而言)
void HeapAdjust(HeapType *H, int s, int m)
{
	RedType rc;
	int j;

	rc = (*H).r[s];
	for(j = 2*s; j <= m; j *= 2)
	{
		// 沿key较大的孩子结点向下筛选
		if(j < m && ((*H).r[j].key < (*H).r[j+1].key))
			++j;	// j为key较大的记录的下标
		if(!(rc.key < (*H).r[j].key))
			break;	// rc应插入在位置s上
		(*H).r[s] = (*H).r[j];
		s = j;
	}
	(*H).r[s] = rc; // 插入
}

// 算法10.11 P282
// 对顺序表H进行堆排序。
void HeapSort(HeapType *H)
{
	RedType t;
	int i;

	// 把H.r[1..H.length]建成大顶堆
	for(i = (*H).length / 2; i > 0; --i)
		HeapAdjust(H, i, (*H).length);
	
	for(i = (*H).length; i > 1; --i)
	{
		// 将堆顶记录和当前未经排序子序列H.r[1..i]中最后一个记录相互交换
		// H.r[1]为堆中最大值,也就是堆顶记录。
		t = (*H).r[1];
		(*H).r[1] = (*H).r[i];
		(*H).r[i] = t;
		// 将H.r[1..i-1]重新调整为大顶堆
		HeapAdjust(H, 1, i-1);
	}
}

#define N 8

int main()
{
	RedType d[N] = {
		{ 49, 1}, { 38, 2}, { 65, 3}, { 97, 4},
		{ 76, 5}, { 13, 6}, { 27, 7}, { 49, 8}
	};
	SqList sl;
	int i;

	for(i = 0; i < N; i++)
		sl.r[i+1] = d[i];
	sl.length = N;
	
	printf("排序前:\n");
	print(sl);

/*****************简单选择排序**********************/
#if 0
	SelectSort(&sl);
	
	printf("简单选择排序后:\n");
	print(sl);
#endif

/*****************树形选择排序**********************/
#if 0
	TreeSort(&sl);
	
	printf("树形选择排序后:\n");
	print(sl);
#endif

/*****************堆排序**********************/
#if 1
	HeapSort(&sl);
	
	printf("堆排序后:\n");
	print(sl);
#endif

	return 0;
}

/*
输出效果:

*****************简单选择排序**********************

排序前:
(49, 1) (38, 2) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)

简单选择排序后:
(13, 6) (27, 7) (38, 2) (49, 1) (49, 8) (65, 3) (76, 5) (97, 4)

请按任意键继续. . .


*****************树形选择排序**********************

排序前:
(49, 1) (38, 2) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)

树形选择排序后:
(13, 6) (27, 7) (38, 2) (49, 1) (49, 8) (65, 3) (76, 5) (97, 4)

请按任意键继续. . .


*****************堆排序**********************

排序前:
(49, 1) (38, 2) (65, 3) (97, 4) (76, 5) (13, 6) (27, 7) (49, 8)

堆排序后:
(13, 6) (27, 7) (38, 2) (49, 1) (49, 8) (65, 3) (76, 5) (97, 4)

请按任意键继续. . .


*/

【上篇】
【下篇】

抱歉!评论已关闭.