您的位置:首页 > 理论基础 > 数据结构算法

堆排序算法及时间复杂度分析

2013-11-28 22:53 260 查看
堆其实通常是通过一维数组来实现的,在数组起始下标为0的情况下,父节点i的左右子节点分别为2*i+1和2*i+2,子节点i的父节点为(i-1)/2。对堆的操作主要有建堆、调整堆、堆排序、插入和删除堆中元素。其中调整堆是核心。下面将重点介绍两种调整堆的方法。

向下调整堆(shift函数):

向下调整堆即为从某一节点开始,若其存在子节点,则与其子节点中最大的相比,若比其最大子节点小,则先保存其值,再将其用其最大子节点替代,同时将待调整点下标换为其最大子节点的。重复上述步骤,直到其没有子节点或保存的值比其最大子节点大为止,最后将先前保存在值赋给最后结束时的待调整点。

向下调整堆一般用在建堆和堆排序中,建堆时从最后一个叶节点的父节点依次往前进行向下调整。堆排序时先进行建堆,然后将最后一个元素与第一个元素对调,对第一个元素向下调整。

向上调整堆(shift_up函数)

向上调整堆主要是用在在已建好的堆中插入元素的时候,算法如下,先保存待调整点的值,若其存在父节点,将其与其父节点相比,若其值大于其父节点则将父节点的值赋给它,将待调整点的下标换成父节点的,重复以上过程知道其没有父节点或者保存值小于其父节点的值为止,最后将保存的值赋给循环结束时的待调整点。

插入操作是通过向上调整实现的,再堆的最后添加一个要插入的元素,将其向上调整至合适的位置;

删除操作是通过向下调整实现的,将待删除元素和最后一个调换,堆大小减1.这时候我们不能盲目的就向下调整待调整点,需要判断一下。若其无父节点或父节点为根节点或待调整点小于父节点,则向下调整,反之则需向上调整。

时间复杂度我们简单的说一下,为o(nlogn)。

代码如下:

#include<iostream>
#define MAXSIZE 100
using namespace std;

void shift(int *heap,int heapsize,int i)//heap为指向数组(堆)首地址的指针,heapsize为堆的大小,i标记需要移动的数据在数组中的下标
{
int temp=heap[i];
int c=2*i+1;//得到i的左孩子下标
while(c<heapsize)
{
if(c+1<heapsize&&heap[c+1]>heap[c])
{
c++;
}
if(heap[c]>temp)
{
heap[i]=heap[c];
i=c;
c=2*i+1;
}
else
{
break;
}
}
heap[i]=temp;
return;
}

void buildheap(int *heap,int heapsize)//建堆,由下向上调整
{
int i=(heapsize-2)/2;//根据完全二叉树的性质,最后一个叶节点的父节点为(heapsize-2)/2
for(;i>=0;i--)
{
shift(heap,heapsize,i);
}
}

void heapsort(int *heap,int heapsize)
{
int i=0;
int temp;
//buildheap(heap,heapsize);
for(i=heapsize-1;i>0;i--)
{
temp=heap[0];
heap[0]=heap[i];
heap[i]=temp;

shift(heap,i,0);
}
}

void delete_i(int *heap,int &heapsize,int i)//删除第i个元素,用最后一个元素与第i个元素替换,然后做出调整
{
if(i<0||i>=heapsize)
{
return;
}
int last=heap[heapsize-1];
heapsize--;
if(i==heapsize) return;//要删除的就是最后一个,直接将heapsize-1即可
heap[i]=last;
int f=(i-1)/2;
if(f==0||heap[f]>=heap[i])
{
shift(heap,heapsize,i);
}
else
{
shift_up(heap,heapsize,i);
}
}
int delete_max(int *heap,int heapsize)
{
int ret=heap[0];
delete_i(heap,heapsize,0);
return ret;
}

void shift_up(int *heap,int heapsize,int i)
{
if(i==0)
return;
int f=(i-1)/2;
int temp=heap[i];
while(f>=0&&i!=0)
{
if(temp>heap[f])
{
heap[i]=heap[f];
i=f;
f=(i-1)/2;
}
else
{
break;
}
}
heap[i]=temp;
}

void insert(int *heap,int &heapsize,int data)//将数据data插入合适的位置
{
if(heapsize>=MAXSIZE)
{
cout<<"空间已满"<<endl;
return;
}
heapsize++;
heap[heapsize-1]=data;
shift_up(heap,heapsize,heapsize-1);
}

int main()
{
int heap[MAXSIZE]={3, 5, 3, 6, 4, 7, 5, 7, 4};
int length=9;
buildheap(heap,length);

//heapsort(heap,length);
cout<<"建堆结果"<<endl;
for(int i=0;i<length;i++)
{
cout<<heap[i]<<" ";
}
cout<<endl;
cout<<"插入数据9后的结果"<<endl;
insert(heap,length,9);
for(int i=0;i<length;i++)
{
cout<<heap[i]<<" ";
}
cout<<endl;
cout<<"删除第二个数据后的结果"<<endl;
delete_i(heap,length,1);
for(int i=0;i<length;i++)
{
cout<<heap[i]<<" ";
}
cout<<endl;
cout<<"堆排序后的结果"<<endl;
heapsort(heap,length);
for(int i=0;i<length;i++)
{
cout<<heap[i]<<" ";
}
cout<<endl;
system("pause");
return 0;
}参考文献:维基百科-堆排序
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息