tournamentsort

来源:互联网 发布:仙剑奇侠传3mac打不开 编辑:程序博客网 时间:2024/06/10 01:58
/* * szlTournamentSort.h */#ifndef SZL_TOURNAMENT_H#define SZL_TOURNAMENT_H/* * 锦标赛排序 * 时间复杂度:O(nlog(n)) * 空间复杂度:O(n) */ void tournament(int a[], int n); #endif
/* * szlTournamentSort.c */#include "szlTournamentSort.h"#include <stdlib.h>#include <assert.h>#include <limits.h>/* * 锦标赛排序 * 时间复杂度:O(lgN) * 空间复杂度:O(n) * 1.首先以n个元素为叶子节点建立一颗完全二叉树;(有技巧:叶子节点数量确定的完全 * 二叉树是并不一定是唯一确定的,但是如果给定叶子节点数量必须比非叶子节点数量 * 多1个而且只多1个,那么这棵二叉树就是完全确定的); * 1.1将当前叶子节点两两比较,将其父节点设置为较大的孩子节点,以此类推; * 1.2得到的这棵树中,树根节点就是所有n个节点中的最大值; * 1.3将这个树根节点对应的叶子节点的值设置为最小值,沿着该节点往树根方向逐个比较; * 并将节点之较大的拷贝给父节点; * 1.4最后得到的树根节点即为当前叶子节点中的最大节点; * ... * 直到最后只剩下一个其值未被修改的叶子节点;删除节点的顺序就是已排好序的一列元素; * 算法分析: * 第1次建立二叉树时需要开辟大小为2*n-1的节点空间,并执行n-1次比较; * 第2次执行了log(2n-1)次比较; * 第3次执行了log(2n-1)次比较; * ... * 第n次执行了log(2n-1)次比较; * 所以时间复杂度为O(2*n-1+(n-1)*log(2*n-1)) = O(n*log(n)); */void tournamentSort(int a[], int n){  /*   * 使用数组来存储一棵完全二叉树;   * 如果使用索引为0的元素(以下称为节点0)表示n个节点的完全二叉树的树根,那么;   * 1.节点i的孩子为节点2*i+1及2*i+2;   * 2.节点i的父节点为(i-1)/2;   * 3.左孩子为奇数索引的节点,右孩子和树根为偶数索引的节点;   * 4.第一个叶子节点是节点n/2;   * 5.最后一个内部节点为n/2-1;   * 6.叶子节点的数量(n-n/2)要么和内部节点数量(n/2)相等,要么比内部节点数量多1;我们   * 这里使用的是叶子数量较内部节点数量多1个完全二叉树;   */      int f,i,j,k;      /*    * 定义结构体保存树中叶子的索引,用于稍后修改叶子的值;*/   typedef struct _treeNode{     int value; // 树节点的值 int index; // 保存value的叶子节点在实现这棵树的数组中的索引   }TreeNode,*ptrTreeNode;      ptrTreeNode tree;      tree = (ptrTreeNode)malloc(sizeof(TreeNode)*(2*n-1));   assert(NULL!=tree);      /*    * 将数组元素拷贝到叶子中去*/   for(i=0,j=n-1;i<n;i++,j++){     tree[j].value = a[i]; // 保存数组的值 tree[j].index = j; // 记住当前叶子节点的在数组中的索引   }      /*    * 第1轮:由最底层的最后一个叶子开始,自底向上,构造一颗树;* 相当于是从后往前扫描元素然后作比较的;* 亦即从这棵树的最后一个内部节点开始,内部节点逐个被赋值;*/   for(i=2*n-2;i>=1;i=i-2){     /*  * 父节点设置为较大的元素  */     if(tree[i].value < tree[i-1].value){   tree[(i-1)/2].value = tree[i-1].value;   tree[(i-1)/2].index = tree[i-1].index; } else{ // tree[i-1]<=tree[i]   tree[(i-1)/2].value = tree[i].value;   tree[(i-1)/2].index = tree[i].index; }   } // 树根节点已经是最大值       /*    * 然后从该叶子节点开始往根节点方向回溯n-1轮;每回溯一次产生一个最大值*/   for(i=0;i<n-1;i++){     /*      * 取出第树根元素,然后放到数组a的末尾  */     a[n-1-i] = tree[0].value;   /*      * 记住取出的元素在树的叶子节点的索引  */     j = tree[0].index;     /*      * 并将取出的节点对应的叶子设置为最小值  */     tree[j].value = INT_MIN;      do{   /*    * 该节点的兄弟节点    */       k = (j&1)?(j+1):(j-1);   /*    * 父节点    */   f = (k-1)/2;   /*    * 设置父节点的值和索引*/   if(tree[j].value < tree[k].value){     tree[f].value = tree[k].value; tree[f].index = tree[k].index;   }   else{ //tree[j].value > tree[k].value     tree[f].value = tree[j].value; tree[f].index = tree[j].index;      }      j=f; //往上一层 }while(f);   }     /*    * 最后一个元素    */   a[0] = tree[0].value;      /*    * 释放空间*/   if(tree){     free(tree);   }}

关于那棵二叉树:



和其他O(n*log(n))的算法运行比较还是不错的。



另一个版本:

/* * tournamentsort.c * space: O(n) * time : O(logn) */#include <stdio.h>#include <limits.h>#define N 30void tournamentsort (int a[], int n){    int j;    int me;    int father;    int sibiling;    int max_child;    int value[2*N-1];    int index[2*N-1];        for (j = n - 1; j < (2 * n - 1); j++){        value[j] = a[j-n+1];        index[j] = j;    }    for (j = 2 * n - 2; j >= 2; j -= 2){        max_child = value[j] > value[j-1] ? j : (j-1);        father = (j - 1) / 2;        index[father] = index[max_child];  /* bugs occurs here */        value[father] = value[max_child];     }    for (j = n-1; j > 0; j--){        a[j] = value[0];        me = index[0];        value[me] = INT_MIN;        do{            sibiling = (1 & me) ? (me + 1) : (me - 1);            father = (me - 1) / 2;            index[father] = value[sibiling] > value[me] ? index[sibiling] : index[me]; /* bugs occurs here */            value[father] = value[index[father]];            me = father;        } while (me);    }    a[0] = value[0];}int main (int argc, char ** argv){    int n;    int i;    int a[N];#ifdef DEBUG1    freopen ("in.txt", "r", stdin);#endif    scanf ("%d", &n);    for (i=0; i<n; i++)        scanf ("%d", &a[i]);    tournamentsort (a, n);    for (i=0; i<n; i++)        printf ("%d ", a[i]);    #ifdef DEBUG1    fclose (stdin);#endif    return 0;}


原创粉丝点击