首页 > 代码库 > 算法学习之排序算法:选择排序

算法学习之排序算法:选择排序

选择排序:每一趟在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:libing1209@126.com
 @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


算法学习之排序算法:选择排序