zoukankan      html  css  js  c++  java
  • 算法导论 第六章 堆排序

    算法导论第六章  堆排序
    一 概念
    1.(二叉)堆是数据结构的一种数组对象(堆是数组而不是一般的树)
    2.但它可以视为一棵完全二叉树,二叉树的层次遍历对就数组元素的顺序对应,树根对应A[1],
      对于第i个元素,有以下主要关系:
     PARENT(i)  return i/2    // its parent
     LEFT(i)  return 2*i    // its left child
     RIGHT(i) return 2*i+1
    3.最大堆(根结点最大):
      A[PARENT(i)] >= A[i];    // 父结点不小于子结点
      最小堆:
      A[PARENT(i)] <= A[i];    // 父结点不大于子结点
    4.堆的高度:
      从本结点到叶子结点的最长简单下降路径上边的数目,定义堆的高度为树根的高度,叶子结点高度为0,对于n个结点的堆,高度为 floor(lgn)即lgn向下取整数

    二。堆的数据结构
    1. A[N]: 堆数组
       length[A]: 数组中元素的个数
       heap-size[A]: 存放在A中的堆的元素个数
    2. 操作:
     (1)MAX—HEAPIFY(A,i)过程O(lgn),保持最大堆性质的关键
     (2)BUILD—MAX—HEAP 过程O(n),构造最大堆
     (3)HEAPSORT 运行时间O(n*lgn),对数组进行排序
     (4)堆运用于优先级队列:
       MAX-HEAP-INSERT(A, val)    // insert a element to A
       HEAP-EXTRACT-MAX(A)            // remove and return the max element of A
       HEAP-INCREASE-KEY(A, i, ival) // increase the ith element's val to ival
       MAXIMUM(A)  // return the element which has the greatest val

      

    三,程序实现

    #include <stdio.h>
    #include <stdlib.h>
    
    #define PARENT(i)	(i) >> 1		// parent of i
    #define LEFT(i)		(i) << 1		// left child of i
    #define RIGHT(i)	((i)<<1) + 1	// right child of i
    
    #define MINVAL	(signed)(1 << 31)
    
    static int heap_size = 0;
    static int length = 0;
    
    /*
     * 以LEFT(i)和RIGHT(i)为根的两棵二叉树都是已建好的最大堆
     * 但A[i]可能小于其孩子,此时对其"下降"调整使满足最大堆性质
     * recusion Version
     */
    void max_heapify(int *heap, int i)
    {
    	int	l, r, largest;
    	l = LEFT(i);
    	r = RIGHT(i);
    
    	if (l <= heap_size && heap[l] > heap[i])
    		largest = l;
    	else
    		largest = i;
    
    	if (r <= heap_size && heap[r] > heap[largest])
    		largest = r;
    	
    	if (largest != i) {	// need to be adjusted
    		int	t = heap[i];
    		heap[i] = heap[largest];
    		heap[largest] = t;
    		max_heapify(heap, largest);
    	}
    }
    
    /* not recursion version */
    void max_heapify02(int *heap, int i)
    {
    	int	l, r, largest;
    	int	t;
    
    	while (1) {
    		l = LEFT(i);
    		r = RIGHT(i);
    
    		if (l <= heap_size && heap[l] > heap[i])
    			largest = l;
    		else
    			largest = i;
    
    		if (r <= heap_size && heap[r] > heap[largest])
    			largest = r;
    
    		if (largest != i) {
    			t = heap[largest];
    			heap[largest] = heap[i];
    			heap[i] = t;
    			i = largest;
    		} else
    			break;
    	}
    }
    
    void build_max_heap(int *heap)
    {
    	int	i;
    
    	for (i = heap_size / 2; i >= 1; i--)
    		max_heapify(heap, i);
    }
    
    void heapsort(int *heap)
    {
    	int	i, t;
    
    	build_max_heap(heap);
    	for (i = length; i >= 2; i--) {
    		t = heap[i];
    		heap[i] = heap[1];
    		heap[1] = t;
    		heap_size--;
    		max_heapify(heap, 1);
    	}
    	heap_size = length;
    }
    
    int heap_maximum(int *heap)
    {
    	return heap[1];
    }
    
    int heap_extract_max(int *heap)
    {
    	int	max;
    
    	if (heap_size < 1) {
    		fprintf(stderr, "heap underflow\n");
    		exit(0);
    	}
    	max = heap[1];
    	heap[1] = heap[heap_size];
    	heap_size--;
    	max_heapify(heap, 1);
    	
    	return max;
    }
    
    /* the key must not less then the original val heap[i] */
    void heap_increase_key(int *heap, int i, int key)
    {
    	int	t;
    	if (i < 1 || i > heap_size) {
    		fprintf(stderr, "invalid position of %d\n", i);
    		exit(-1);
    	}
    	if (key < heap[i]) {
    		fprintf(stderr, "new key is smaller than current key\n");
    		exit(-1);
    	}
    	
    	while (i > 1 && key > heap[PARENT(i)]) {
    		heap[i] = heap[PARENT(i)];
    		i = PARENT(i);
    	}
    	heap[i] = key;
    }
    
    void max_heap_insert(int *heap, int key)
    {
    	heap_size++;
    	heap[heap_size] = MINVAL;
    	heap_increase_key(heap, heap_size, key);
    }
    
    void print_heap(int *heap)
    {
    	int	i;
    	for (i = 1; i <= heap_size; i++)
    		printf("%3d ", heap[i]);

    printf("\n"); } int main() { //int arr[] = { 0, 10, 9, 2, 100, 300, 56, 67, 3, 2, 2, 20, 10 }; int arr[] = { 0, 100, 2, 20, 10 }; int i, x; length = sizeof(arr) / sizeof(*arr) - 1; heap_size = length; printf("original array:\n"); print_heap(arr); build_max_heap(arr); printf("max heap:\n"); print_heap(arr); /* printf("after sorted:\n"); heapsort(arr); print_heap(arr); */ printf("after extract max:\n"); heap_extract_max(arr); print_heap(arr); x = 33; printf("insert %d to the heap:\n", x); max_heap_insert(arr, x); print_heap(arr); return 0; }


    四,部分习题解答:

    6.1-1: 2^(h+1) 2^h
    6.1-2: 含n个元素的堆的高度为 lgn 取下整数
      1+2+4+...+2^(h-1) < n <= 1+2+4+..2^h
      (1-2^h)/(1-2) < n <= (1-2^(h+1))/(1-2)   
      2^h-1 < n <= 2^(h+1)-1 --> 2^h <= n < 2^(h+1)
      --> h <= lgn < h+1    --> h = floor(lgn)
    6.1-3: 由堆的定义可得
    6.1-4:叶子结点
    6.1-5: No
    6.1-6:no
    6.1-7: 最后一个结点n的父结点为n/2,其父结点之后为叶子结点

    6.2-2:minmum heap
     MIN-HEAPIFY(A, i)
      l = LEFT(i)
      r = RIGHT(i)
      if l <= heap-size[A] and A[l] < A[i]
         smallest = l;
      else
        smallest = i;
      if r <= heap-size[A] and A[r] < A[smallest]
        smallest = r
      if smallest != i
        A[i] <-> A[smallest]
        MIN-HEAPIFY(A, smallest)
    6.2-3:
      程序执行一次测试立刻退出,不改变堆
    6.2-4:
      一次测试后立刻退出,堆不变
    6.2-5:
      见上面代码 not recursion ersion
    6.2-6:
      一直不知道证明???

    6.3-2:
      从下至上建堆,可以利用建好的堆调用MAX-HEAPIFY
    6.3-3:
      n <= 2^(h+1)
      第0层最多 2^h
      第1层最多 2^(h-1)
      ...
      第h层(根层) 1 >= n / (2^(h+1))

    6.5-7:
      因为insert程序调用HEAP—INCREASE—KEY(),而increase函数要求插入的key大于原来的值,所以先把原来的值设为最小值。
    6.5-8:
      见堆排序k路合并


    思考题

    6-1: 用插入法建堆
       BUILD-MAX-HEAP02(A)
    	heap-size[A] = 1
    	for i = 2 to length[A]
    		MAX-HEAP-INSERT(A, A[i])
    
      MAX-HEAP-INSERT(A, A[i])
    	同上
     a) 不一样 A = { 1, 2, 3 }
    
    6-2: d叉堆的分析
      d叉堆与二叉堆类似,只是其中每一个非叶子结点有d个子女
      PARENT(i) = (i-2)/d + 1
      LEFTMOST(i) = d*(i-1) + 2
      //RIGHTMOST(i) = d*i+1
      CHILD(i, j) = d * (i-1) + j + 1
    a) 根结点为A[1],根结点的孩子为A[2],A[3]...A[d+1] 
    b) lgn / lgd
    c) O(lgn/lgd * d)
      EXTRACT-MAX(A)
    	max = A[1]
    	A[1] = A[heap-size[A]]
    	heap-size[A] = heap-size[A]-1
    	MAX-HEAPIFY(A, 1)
    其中:
    MAX-HEAPIFY(A, i)
      l = LEFTMOST(i)
      r = RIGHTMOST(i)
      largest = i;
      while (l <= r && l <= heap-size[A])
    	if (A[l] > A[largest])
    		largest = l
    		l <- l+1
    	
      if largest != i
     	A[i] <-> A[largest]
    	MAX-HEAPIFY(A, largest)
    d) lgn / lgd
       MAX-HEAP-INSERT(A, key)
    	heap-size[A] <- heap-size[A] + 1
    	A[heap-size[A]] <- 无穷小
    	HEAP-INCREASE-KEY(A, heap-size[A], key)
    e) lgn / lg d
       HEAP-INCREASE-KEY(A, i, key)
    	//if key < A[i]
    	//    then error "new key is samller than current key"
    	// A[i] <- key
    	//while i > 1 and A[PARENT(i)] < A[i]
    	//  do 	exchange A[i] <-> A[PARENT(i)]
    	//	i <- PARENT(i)
    	key <- MAX(A[i], key)	
    	while i > 1 and A[PARENT(i)] < key
    	   do A[i] <- A[PARENT(i)]
    	      i = PARENT(i)
            A[i] = key




  • 相关阅读:
    [HAOI2008] 硬币购物
    [HNOI2002] Kathy 函数
    [SCOI2009] windy数
    圆方树总结
    ABOUT ME && 友链
    逝念偶拾
    文化课日常
    记一些欢愉
    浅谈
    洛谷 4823 [TJOI2013]拯救小矮人
  • 原文地址:https://www.cnblogs.com/huiqin/p/3674857.html
Copyright © 2011-2022 走看看