简单选择排序与堆排序

来源:互联网 发布:翻转课堂软件 编辑:程序博客网 时间:2024/04/28 07:54

选择排序的基本运算都是在n个元素组成的序列中,选择一个关键字最大或最小的元素输出,然后再从剩余的n-1个元素中选择一个关键字最大或最小的元素输出,以此类推,直到排序结束。
以递增排序为例,简单选择排序过程如下:1第一次在数组中查找最小值a[i],然后将a[i]和a[0]交换位置。
2从a[1]开始,同样从a[1]开始往后找到最小值a[j],然后与a[1]交换位置,依次类推。
废话不多说,直接贴代码

//**************5简单选择排序************************//比冒泡法交换的次数少,比较多,交换少void SelectSort(int a[],int len){int i,j,min,temp;for(i=0;i<len-1;i++){min=i;for(j=i+1;j<len;j++)if(a[j]<a[min])min=j;temp=a[i];a[i]=a[min];a[min]=temp;}}

简单选择排序    时间复杂度O(n^2)    

稳定性分析选择排序是给每个位置选择当前元素最小(或最大)的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个 元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果当前元素比一个元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么 交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法。

简单选择排序的时间主要浪费在对于n个元素(乱序)如何----在小于O(n)时间内查找最大值或最小值

改进:堆排序

堆是一棵完全二叉树,其中任一非叶子节点的关键字均大于(或小于)等于其孩子节点的关键字。分为最大堆和最小堆

用最大堆进行升序排序:先构造初始最大堆,由于最大堆的第一个关键字就是最大值,直接将第一个关键字和最后一个关键字交换(是不是和简单选择排序很相似),然后再调整其余关键字,使其重新构成最大堆,然后再将第一个关键字与当前最大堆的最后一个关键字交换,依次类推,直到排序完成。

简而言之就是: 构造初始堆---->取堆顶------>调整剩余堆------>取剩余堆顶------->.........-------->空堆end

构造初始堆的过程描述如下:


废话不多说,直接上代码:

//*****************6堆排序*******************************//升序排序构造大顶堆,每次把最大元素(根)放在数组最后一个位置//对于剩余元素重新构造二叉堆-----以数组形式存储堆 (完全二叉树)void HeapAdjust(int a[], int i, int size) {//调整堆(大小为size--a[0~size])的第i个节点使之为大顶堆  size=len-1;节点编号0,1,...size.int lchild = 2*i+1;//i的左孩子节点序号int rchild = 2*i+2;//i的右孩子节点序号int max=i;int temp;if(i<=size/2)//如果i是叶节点就不用进行调整{if(lchild<=size && a[lchild]>a[max])max=lchild;if(rchild<=size && a[rchild]>a[max])max=rchild;if(max!=i){temp=a[i];a[i]=a[max];a[max]=temp;//避免调整之后以man为父节点的子树不是大顶堆HeapAdjust(a,max,size);  }}}void HeapSort(int a[],int size){//HeapSort(a,9);size=n-1;不是元素个数int i,temp;for(i=size/2;i>=0;i--)//建立初始堆 非叶子节点最大序号值为size/2   HeapAdjust(a,i,size);for(i=size;i>=0;i--){temp=a[0];   //交换堆顶和最后一个元素a[0]=a[i];a[i]=temp;//BuildHeap(a[],i-1);//将余下元素重新建立为大顶堆HeapAdjust(a,0,i-1);//重新调整堆顶节点成为大顶堆}}

由于堆是完全二叉树,其实还是用数组来描述堆。。。。。

下面对代码进行解释:

HeapSort第一个for循环就是建立堆的过程,从第一个非叶子节点开始进行调整堆(HeapAdjust)最后一个个非叶子节点可能是size/2,可有可能是size/2-1,至于为什么从编号为size/2开始,是为了保证最大可能性,进一步的确定是不是叶子节点可在HeapSort中的if(lchild<=size)等中进行判断。

HeapSort第二个for循环就是取堆顶,调整堆的过程。


下面分析时间复杂度(参考算法导论)


分析调整堆的时间复杂度

重调堆,时间复杂度为T(lgn)

堆排序的时间复杂度T(nlgn)  无论最好最坏都是一样的




1 0
原创粉丝点击