堆排序

来源:互联网 发布:xp与linux双系统 编辑:程序博客网 时间:2024/06/01 07:51


堆是一个完全二叉树的数组对象。树每一层都是满的,最后一层可能除外。

最大堆:父节点关键字不小于两个子节点的关键字;

最小堆:父节点关键字不大于两个子节点的关键字。

堆一般存储在数组中,根节点可以从下标0或1开始。

下标从0开始:父节点位置 i ,左右子节点位置为 (i+1)*2 - 1;  (i+1)*2。

下标从1开始:父节点位置 i ,左右子节点位置为     i*2 ;  i*2+1。

 

堆排序思路:对于数组中a的元素a[0~n-1],首先把数据最大堆化,交换a[0]与a[n-1],即删除最大堆的根节点,放到后面,然后再把删除后的堆调整为最大堆。循环这个过程知道堆中只有一个元素。(完成后就是一个从小到大排列的数组了)。

 

堆得插入:

          (1)堆得大小加1,将数据放到堆的最后一个位置。

          (2)调整为堆:与父节点比较,如果值比父节点大,着交换父子节点;重复这个过程直到父节点比子节点大或者到达根节点。

堆的删除:

          (1)取出根节点。将最后一个节点放到根节点出。

          (2)从根节点开始向下调整为最大堆:找出值最大的儿子,如果该值比父节点大,则交换;重复直到不满足条件或者到达堆尾。

 

#define MAX_SIZE 200#define HEAP_FULL(n) (n >= MAX_SIZE - 1)#define HEAP_EMPTY(n) (n == 0)typedef struct Heap{int data[MAX_SIZE];  //数据可以用指针,然后动态内存分配。这样根据情况调整数组大小int size;}Heap;void initHeap(Heap *heap){heap->size = 0;}
//最大堆得插入,元素下标从1开始的情况
void insertHeap(Heap *heap, int element){int i;if(HEAP_FULL(heap->size)){printf("heap is full...\n");return;}heap->size++;i = heap->size;while((i != 1) && (element > heap->data[i/2]) ){heap->data[i] = heap->data[i/2];i /= 2;}heap->data[i] = element;}int deleteHeap(Heap *heap){int item,tmp;int parent = 1,child = 2;if(HEAP_EMPTY(heap->size)){printf("heap is empty...\n");exit(0);}item = heap->data[1];tmp = heap->data[heap->size--];   //指向堆得最后一个元素。  size减1while(child <=heap->size){if((child < heap->size) && (heap->data[child] < heap->data[child + 1]))child++;if(tmp >= heap->data[child])break;heap->data[parent] = heap->data[child];parent = child;child *= 2;}heap->data[parent] = tmp;   //将最后第一个插入到这里。return item;}


 将数组调整为最大堆:

         从最后一个有子节点的节点向前开始最大堆化,根据完全二叉树的特性:有儿子的节点=(没有儿子的节点)或者(没有儿子的节点+1)。因此最后一个有子节点的元素位置为 i=(n-1)/2 (注:相对于根节点从0开始的情况,如果是从1开始,则为i = n/2。其中n为堆最后一个元素的下标)。

 

void siftdown(int a[], int i, int n) { int j; int t= a[i];while((j = 2*i + 1 ) < n) {if(j<n-1 && a[j] < a[j + 1]) j++; //两子女中选大者 if(t<a[j]) { a[i] = a[j];i = j; } else break; } a[i] = t;}//根节点从0开始。这里的n是数组长度void heap (int a[], int n) {int i; for(i= (n-2)/2; i>=0; i--) siftdown(a, i, n); //调整为堆}


 

0 0