您的位置:首页 > 其它

简单选择排序与堆排序

2015-05-07 12:51 218 查看

选择排序的基本运算都是在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) 无论最好最坏都是一样的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐