选择排序:每一趟在n-i+1(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录。
一、简单选择排序
一趟选择排序操作:
通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换之。
对L[1...n]中记录进行简单选择排序的算法为:令i从1至n-1,进行n-1趟选择操作。简单选择排序过程中,所需进行记录移动的操作次数较少,然而,无论记录的初始排列如何,所需关键字间的比较次数相同。因此,总的时间复杂度为O(n^2)。
示例代码(C语言描述):
/********************************************************************* Author:李冰 date:2014-9-11 Email:[email protected] @array: the pointer to the records @length:the length of the records *********************************************************************/ //交换数据 void Swap(int *num1, int *num2) { int tmp = *num1; *num1 = *num2; *num2 = tmp; } void SelectSort(int array[], int length) { if(array == NULL || length <= 0) return; int i, j, index; for(i = 0; i < length; i++){ index = i; for(j = i + 1; j < length; j++) if(array[j] < array[index]) index = j; if(i != index) Swap(&array[i], &array[index]); } }
二、树形选择排序(锦标赛排序)
树形选择排序又称锦标赛排序。首先对n个记录的关键字进行两两比较,然后在其中n/2个较小者之间再进行两两比较,如此重复,直至选出最小关键字的记录为止。该过程可用一颗有n个叶子结点的完全二叉树表示。
代码示例(C语言描述):
/* * 对树进行筛选:从叶子节点开始,两两一起选出最小的,作为双亲 */ static void AdjustTree(int *Tree,int length,int high){ /*调整至根节点,结束调整*/ if(length==1){ return; } else{ int nextlength=(length+1)/2; int adjustpos=high-length+1-nextlength; /*选择两个叶子,选择其中较小的作为两个叶子的双亲*/ for(int i=high-length+1;i<=high;i+=2){ /* * 可能最后一个选择时,只有一个叶子,即奇数个叶子 * 依然应该把剩下的叶子Tree[i]作为自己的双亲 * 所以 i<high 不能丢 */ if( (i<high)&&(Tree[i]>Tree[i+1]) ){ Tree[adjustpos]=Tree[i+1]; } else{ Tree[adjustpos]=Tree[i]; } adjustpos++; } AdjustTree(Tree,nextlength,high-length); } } /* * 根据最底层节点个数n,返回整棵树的节点数 */ static int GetTreeSize(int n){ if(n==1){ return 1; } else{ return (n+GetTreeSize((n+1)/2)); } } /* * 对sq+1,sq+2,sq+3,...,sq+length 进行树形选择排序 */ void TreeSelectSort(int *sq,int length){ /*根据叶子节点数为length,创建一个二叉树,用顺序存储结构表示*/ /* 7个叶子,需要节点数为 7+4+2+1=14 O / O O /\ / O O O O /\ /\ /\ / O OO O O OO */ /*Tree指向这个二叉树的指针,TreeSize保存二叉树的节点总数*/ int TreeSize=0; int *Tree=NULL; TreeSize=GetTreeSize(length); //printf("\nTreeSize=%d\n",TreeSize); Tree=(int *)malloc(TreeSize*sizeof(int)); if(Tree!=NULL){ memset(Tree,0,TreeSize*sizeof(int)); //复制序列到树结构中 for(int i=TreeSize-length,j=1;i<TreeSize;i++,j++){ Tree[i]=sq[j]; } for(int pos=1;pos<=length;){ AdjustTree(Tree,length,TreeSize-1); printf("Min node =%d\n",Tree[0]); //选出所有关键字等于当前最小的记录,填到结果中 for(int i=TreeSize-length;i<TreeSize;i++){ if(Tree[i]==Tree[0]){ Tree[i]=MAX_INT; /* * 20120910更改此处的 break * 原因是:如果有大量数据重复,对每个重复的数据也进行选择效率太低 * 对一个关键字选择后,对所有关键字等于这个关键字的记录都应不再进行选择 */ //break; sq[pos]=Tree[0]; pos++; /* * 注意这点:pos++ 的位置,并没有放在for循环中 * 因为每次筛选出来的最小关键字肯定存在于叶子节点中 * if(Tree[i]==Tree[0])至少成立一次 * 如果不止成立一次,即有相同关键字,则应该减少筛选次数 */ } } } free(Tree); Tree=NULL; } }
由于含有 n 个叶子节点的完全二叉树的深度为 『( log2(N) )+1 ,则在树形选择排序中除最小关键字之外,每选择一个次小关键字仅需进行 『( log2(N) )次比较,因此它的时间复杂度为 O(NlogN)。『代表上取整
参考文献:
1、《数据结构(C语言描述)》
严蔚敏 吴伟东 编著
2、http://blog.csdn.net/to_be_it_1/article/details/37866391
3、http://blog.csdn.net/zhccl/article/details/7960983
4、http://blog.csdn.net/morewindows/article/details/6671824
时间: 2024-12-14 05:31:50