CLRS2e读书笔记—Chapter6

 
 1 /*-----------Heap-Sort implemented in C------------------*/
 2 
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 
 6 inline int left(int i)
 7 {
 8     //C语言中下标从0开始
 9     return (i<<1)+1;
10 }
11 inline int right(int i)
12 {
13     return (i<<1)+2;
14 }
15 inline int parent(int i)
16 {
17     return (i-1)>>1;
18 }
19 void swap(int* A,int i,int j)
20 {
21     int temp=A[i];
22     A[i]=A[j];
23     A[j]=temp;
24 }
25 void max_heaptify(int* A,int i,int n)
26 {
27     int l=left(i);
28     int r=right(i);
29     int largest;
30     if(l<n && A[l]>A[i])
31         largest=l;
32     else
33         largest=i;
34     if(r<n && A[r]>A[largest])
35         largest=r;
36     if(largest != i)
37     {
38         swap(A,i,largest);
39         max_heaptify(A,largest,n);
40     }
41 }
42 void build_max_heap(int* A,int n)
43 {
44     //这里的下标计算也要小心
45     int i=(n-2)/2;
46     for(;i>=0;--i)
47     {
48         max_heaptify(A,i,n);
49     }
50 }
51 void heap_sort(int* A,int i,int n)
52 {
53     build_max_heap(A,n);
54     while(n>0)
55     {
56         swap(A,0,n-1);
57         --n;
58         max_heaptify(A,0,n);
59     }
60 
61 }
62 //所有排序的主函数保持形式上的一致性
63 int main()
64 {
65     int A[30];
66     int i=0;
67     printf("Original:\n");
68     for (;i<30;i++)
69     {
70         A[i]=rand();
71         printf("%d\t",A[i]);
72     }
73     heap_sort(A,0,30);
74     printf("\nRearrange:\n");
75     for(i=0;i<30;++i)
76     {
77         printf("%d\t",A[i]);
78     }
79 }
 1 inline int heap_maximum(int* A)
 2 {
 3     return A[0];
 4 }
 5 int heap_extract_max(int* A,int size)
 6 {
 7     if(size<=0) exit(-1);
 8     int max=A[0];
 9     swap(A,0,size-1);
10     --size;
11     max_heaptify(A,0,size);
12     return max;
13 }
14 void heap_increase_key(int* A,int i,int key,int size)
15 {
16     if(i>=size)exit(-1);
17     if(A[i]>key)exit(-2);
18     A[i]=key;
19     int j;
20     while((j=parent(i))>=0 && A[i]>j)
21     {
22         swap(A,i,j);
23         i=j;
24     }
25 }
26 void heap_insert(int* A,int value,int size)
27 {
28     //overflow may happen here
29     size+=1;
30     if(size>=heap_size)exit(-3);
31     A[size-1]=INT_MIN;
32     heap_increase_key(A,size-1,value,size);
33 }
 
上面是优先级队列(用最大堆实现)的相关代码,写的不太好。C的数组不支持动态扩充,可以考虑运用vector的自增长技术来防止溢出。

exercises:

6.1-1 $2^{h+1} \ge n \ge 2^h$,很简单,每层最多有$2^h$个元素,最底层最少有1个元素。

6.1-2 对上式求对数可得。

6.1-3 根据最大堆的定义易推知。

6.1-4 叶子结点。

6.1-5 不是,举例可证。

6.1-6 不是,画出来可以看出来,6和7的顺序反过来才是。

6.1-7 主要根据度为2的结点是度为0的结点个数+1这个结论。

6.2-2 Min-Heapify(A,i)

    l ← LEFT(i)

    r ← RIGHT(i)

    if l <heap-size(A) and A[l]<A[i]

      then smallest ← l

    else smallest ← i

    if r<heap-size(A) and A[r]<A[smallest]

       then smallest ← r

    if i ≠ smallest

       then swap A[i]↔A[smallest]

          Min-Heaptify(A,smallest)

运行时间一致…都是$\Theta(lgn)$

6.2-3 无效果

6.2-4 对叶子结点使用,无效果

6.2-5 将第10行以后改成

    while l ≤ heap-size(A) and r ≤ heap-size(A)

      do if A[l] > A[i]

          then largest ← l

        else largest ← i

        if A[r] > A[largest]

           then largest ← r

        if i≠ largest

           then swap A[i]↔A[largest]

         i ← largest

即可

6.2-6 其实就是从根节点到叶节点全部都要执行一次max-heapify,故时间就是树的深度$\Theta(lgn)$

6.3-2 只有递减才能保证每次交换顺序后,下标在被交换元素后面的堆数据仍保持最大堆性质。

6.3-3 此题注意一点:高度为h的结点,深度是H-h。H是树的总高度。

6.4-3 都是O(nlgn)

6.4-4 最坏情况同max-heaptify的最坏情况。

6.5-3 Min-Heapify的伪代码见6.2-2

Heap-Minimum(A)

return A[1]

Heap-Extract-Min(A)

if heap-size(A)<1

  then error "heap underflow"

min ← A[1]

A[1] ← A[heap-size(A)]

heap-size(A) ← heap-size(A)-1

Min-Heapify(A,1)

return min

Heap-Decrease-Key(A,i,key)

if A[i]<key

  error "new key is bigger then current key"

A[i]=key

while i>1 and A[i]<A[parent[i]]

  do swap A[i]↔A[parent[i]

    i ← parent[i]

Min-Heap-Insert(A,key)

heap-size[A] ← heap-size[A]+1

A[heap-size[A]] ← +∞

Heap-Decrease-Key(A,heap-size[A],key)

6.5-4 设为负无穷大可以保证增加的元素不违反最大堆的特性,从而保证Increase Key的函数能够正常返回

6.5-6 队列是先进先出,可以使用最小堆,先进的元素具有最低的key,后面的递增;

    堆栈是先进后出,使用最大堆,先进的元素仍然具有最低的key,后面的递增。

6.5-7 Heap-Delete(A,i)

    swap A[i] ↔ A[heap-size[A]]

    heap-size(A) ← heap-size(A)-1

    Max-Heapify(A,i)

6.5-8 提取k路链表的根指针,放入数组A,将根指针指向的value作为key对数组进行(最小)堆排序。然后提取A[1],作为排序后的首元素,将A[1]替换为原来的元素指向的链表下一个元素(如果为空,则将数组最后一个元素放在此位置,k-1),再Min-Heapify(A,1)。如此循环直到n个元素全部排序完毕。

Min-Heapify的时间为$\Theta(k)$,循环n次,故中的时间为O(nlgk)。

problems:

6-1 a>不是一样的,可以例证。有些树的兄弟位置会变化;

  b>略

6-2 b>$log_bn$

  c>不过是比较的次数由2次变成了d次,所以复杂度也增加到O($d \times log_bn$),忽略常数因子,与b相同。

  d>基本无变化,复杂度同上

  e>同上

6-3 与堆相似,不同的是比较的对象是元素的上下左右四个元素,其中上左相当于最小堆的parent,下右类似于左右孩子。

  注意d中插入时元素要与上、左中较大的元素交换位置,这样才能保持Young氏矩阵的性质。

  f中似乎可以通过二分和矩阵分块的思想每次减少1/4的问题,这样可以超过题中要求的线性算法。

原文地址:https://www.cnblogs.com/livewithnorest/p/2653414.html