二叉堆
二叉堆的基本操作
数据结构表示:
堆的两个基本操作:
堆关键是理解两个基本操作的实现:
1、 向堆插入一个结点(上升操作):
在堆尾(a[n])插入一个元素,然后不断和父节点(a[i/2])比较,如果比父结点大(大根堆)或小(小根堆)就交换,一直到
堆顶或不再交换就结束。
C语言代码:
1 void push_heap(int a[],int n){ 2 int i = n; 3 int x = a[n]; 4 while(i > 1 && a[i/2] < x){ 5 a[i] = a[i/2]; 6 i /= 2; 7 } 8 a[i] = x; 9 }
(以上代码是大根堆的上升操作,小根堆只需将a[i]>a[j]改为a[i]<a[j]即可)
   具体使用时,先在一维数组后面加入元素,然后调用push_heap函数进行调整。如下面的代码:
1 ++n; 2 a[n]=x; 3 push_heap(a,n);
2、删除节点:
删除堆顶节点(下降操作):
将堆顶节点(堆数组第一个)和堆尾节点(堆数组最后一个)交换,然后删除堆尾节点,将交换后的节点和左右儿子比较大小,交换,
更换节点编号,如此重复,直到满足堆的性质。
C语言代码:
先给一个函数,函数功能是把根为m的非大根堆调整成大根堆,前提条件是这个非大根堆的子堆,也就是根的儿子必须是大根堆。
void heap(int a[],int n,int m){ //n 是数组下标范围,m是需要调整的根的下标 int t; while(m*2 <= n){ m = m * 2; if(m < n && a[m] < a[m+1]){ m++; } if(a[m] > a[m/2]){ t = a[m]; a[m] = a[m/2]; a[m/2] = t; } else break; } }
下面的代码是把一个堆的堆顶去掉,并调整堆。
void pop_heap(int a[],int n){ int x; x = a[1]; a[1] = a[n]; a[n] = x; n--; heap(a,n,1); }
堆排序
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
①先将初始数组a[1...n]建成一个大根堆,此堆为初始的无序区
②再将关键字最大的记录a[1](即堆顶)和无序区的最后一个记录a[n]交换,由此得到新的无序区a[1.n-1]和有序区a[n],且满足a[1..n-1]≤a[n]
③由于交换后新的根a[1]可能违反堆性质,故应将当前无序区a[1..n-1]调整为堆。
然后再将a[1..n-1]中关键字最大的记录a[1]和该区间的最后一个记录a[n-1]交换,由此得到新的无序区a[1..n-2]和有序区a[n-1..n],且满足关系a[1..n-2]≤R[n-1..n],同样要将a[1..n-2]调整为堆。
重复②③的步骤,直到无序区只有一个元素为止,此时a[1..n]就是一个有序的数组了。
C语言代码:
//首先建堆,从最底层的元素开始建堆,一直递推到堆顶,即下标为1的数据元素 void make_heap(int a[],int n){ int i; for(i = n/2; i > 0; --i) heap(a,n,i); } //堆排序 void heap_sort(int a[],int n){ int i; make_heap(a,n);//先把无序的数据建立成堆 for(i = n; i > 1; --i){ int t = a[1]; a[1] = a[i]; a[i] = t; heap(a,n-i,1); } }
堆排的时间复杂度约为O(n*logn)
posted on 2017-04-02 22:25 smallcowboy 阅读(86) 评论(0) 收藏 举报
                    
                
                
            
        
浙公网安备 33010602011771号