树形选择排序
概述:
树形选择排序(又称锦标赛排序),是一种按照锦标赛的思想进行选择排序的方法。首先对n个记录的关键字进行两两比较,然后在n/2个较小者之间再进行两两比较,如此重复,直至选出最小的记录为止。
排序过程:
树形选择排序(Tree Selection Sort),这个过程可用一棵有n个叶子结点的完全二叉树表示。例如,图中的二叉树表示从8个数中选出最小数的过程。
8个叶子结点中依次存放排序之前的8个关键字,每个非终端结点中的关键字均等于其左、右孩子结点中较小的那个关键字,则根结点中的关键字为叶子结点中的最小关键字。
在输出最小关键字之后,根据关系的可传递性,欲选出次小关键字,仅需将叶子结点中的最小关键字(13)改为“最大值”,然后从该叶子结点开始,和其左右兄弟的关键字进行比较,修改从叶子结点到根结点的路径上各结点的关键字,则根结点的关键字即为次小值。
同理,可依次选出从小到大的所有数。
算法性能:
时间复杂度:由于含有n个叶子结点的完全二叉树的深度为[log2n]+1,则在树形选择排序中,除了第一次选择最小关键字需要进行 n-1 次比较以外,每选择一个次小关键字仅需进行[log2n]次比较,因此,它的时间复杂度为O(nlogn)。
空间复杂度:这种排序方法减少了许多排序时间,但是使用了较多的附加存储。
如果有 n 个对象,必须使用至少 2n-1 个结点来存放。最多需要找到满足 的 k ,使用 个结点。每个结点包括排序码、结点序号和比较标志三种信息。所以需要的辅助存储空间较多。
代码:
#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */
typedef int InfoType; /* 定义其它数据项的类型 */
#define INT_MAX 999
/* --------------------------- 待排记录的数据类型 ------------------------------*/
#define MAXSIZE 20 /* 一个用作示例的小顺序表的最大长度 */
typedef int KeyType; /* 定义关键字类型为整型 */
typedef struct
{
KeyType key; /* 关键字项 */
InfoType otherinfo; /* 其它数据项,具体类型在主程中定义 */
}RedType; /* 记录类型 */
typedef struct
{
RedType r[MAXSIZE + 1]; /* r[0]闲置或用作哨兵单元 */
int length; /* 顺序表长度 */
}SqList; /* 顺序表类型 */
/* ------------------------------------------------------------------------------------------*/
void TreeSort(SqList *L)
{ /* 树形选择排序 */
int i, j, j1, k, k1, l, n = (*L).length;
RedType *t;
l = (int)ceil(log(n) / log(2)) + 1; /* 完全二叉树的层数 */
k = (int)pow(2, l) - 1; /* l层完全二叉树的结点总数 */
k1 = (int)pow(2, l - 1) - 1; /* l-1层完全二叉树的结点总数 */
t = (RedType*)malloc(k * sizeof(RedType)); /* 二叉树采用顺序存储结构 */
for (i = 1; i <= n; i++) /* 将L.r赋给叶子结点 */
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 + 1] = t[0]; /* 将当前最小值赋给L.r[i] */
j1 = 0;
for (j = 1; j < l; j++) /* 沿树根找结点t[0]在叶子中的序号j1 */
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 + 1) / 2 - 1; /* 序号为j1的结点的双亲结点序号 */
t[2 * j1 + 1].key <= t[2 * j1 + 2].key ? (t[j1] = t[2 * j1 + 1]) : (t[j1] = t[2 * j1 + 2]);
}
}
free(t);
}
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");
}
#define N 8
void main()
{
RedType d[N] = { {49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8} };
SqList l;
int i;
for (i = 0; i < N; i++)
l.r[i + 1] = d[i];
l.length = N;
printf("排序前:\n");
print(l);
TreeSort(&l);
printf("排序后:\n");
print(l);
}
运行结果: