6.5-1 试说明 HEAP-EXTRACT-MAX 在堆 A={15,13,9,5,12,8,7,4,0,6,2,1} 上的操作过程。
由 HEAP-EXTRACT-MAX
的伪代码和 MAX-HEAPIFY(A,i) :通过不断交换 i 和其孩子数据,从而维持最大堆性质
HEAP-EXTRACT-MAX(A)
if(A.heap-size < 1) //判断堆中元素是否为空
error "堆下溢"
max = A[1] //将根节点元素保存起来
A[1] = A[A.heap_size] //将堆中最后一个元素赋值给第一个元素
A.heap_size = A.heap_size - 1 //堆元素数量减少1
MAX-HEAPIFY(A,1) //保持最大堆的性质
return max //返回最大元素
可知,在堆A中,判空后记录下了max为15,将堆中最后一个元素 1 交换到根节点A[1],堆的大小减一,然后执行 MAX-HEAPIFY(A,1) 即:1和13交换,1和12交换,1和6交换,最后返回max:15
7.1-1 参照图7-1的方法,说明PARTITION在数组A = {13, 19, 9, 5, 12, 8, 7, 4, 21, 2, 6, 11}上的操作过程。
解如下:
7.1-4 如何修改QUICKSORT,使得它能够以非递增序进行排列?
答:修改PARTITION()
中的 A[j] <= x 为 A[j] >= x 即可。
9.3-8 设 X[ 1…n ]和Y[ 1…n ]为两个数组,每个都包含 n 个有序元素。请设计一个 O(lg n) 时间的算法来找出数组X和Y中所有2n个元素的中位数。
分治法:
1、先分别求出X和Y的中位数。当数组中的元素是偶数时,在一个数组中取上中位数,在另一个数组中取下中位数,并且在整个过程中保持不变。在哪个数组中取上中位数,就一直在那个数组中取上中位数,反之亦然。
2、比较两个数的大小,如果相等就返回。如果不等的话,去掉较大中位数所在的那个数组的较大的一半,去掉较小的中位数所在的数组的较小的一半
3、在规模减半的两个数组上递归调用。
4、如果一直没有遇到正好相等的情况,那么递归到最后会剩下四个数,则返回第二个数。因为这两个数组都是有n个元素,所以最终返回的必然是2n个数中的下中位数。
public class SearchMiddle {
static int search(int[] X, int p, int q, int[] Y, int r, int s) {
int midx, midy;
if ((p + 1 == q) && (r + 1 == s)) {
if (X[p] < Y[r])
return (X[q] < Y[r]) ? X[q] : Y[r];
else
return (Y[s] < X[p]) ? Y[s] : X[p];
} else {
if ((q - p) % 2 == 0) { // 数组元素为奇数个
midx = (p + q) / 2;
midy = (r + s) / 2;
} else { // 数组元素为偶数个
midx = (p + q) / 2;
midy = (r + s) / 2 + 1;
}
if (X[midx] < Y[midy])
return search(X, midx, q, Y, r, midy);
else if (X[midx] > Y[midy])
return search(X, p, midx, Y, midy, s);
else
return X[midx];
}
}
// 快速排序
static int Partition(int[] A, int p, int r) {
int x = A[r];
int i = p - 1;
int t;
for (int j = p; j <= r - 1; j++)
if (A[j] <= x) {
i++;
t = A[i];
A[i] = A[j];
A[j] = t;
}
t = A[i + 1];
A[i + 1] = A[r];
A[r] = t;
return i + 1;
}
static void QuickSort(int[] A, int p, int r) {
int q;
if (p < r) {
q = Partition(A, p, r);
QuickSort(A, p, q - 1);
QuickSort(A, q + 1, r);
}
}
static void QSort(int[] A) {
QuickSort(A, 0, A.length - 1);
}
public static void main(String[] args) {
int a[] = {3,5,7,1};
int b[] = {6,8,2,4};
int c[] = {4,5,1,2,3,6,7,8};
QSort(a);
QSort(b);
QSort(c);
int temp = search(a, 0, 3, b, 0, 3);
if (temp != c[3]) {
System.out.println("error!");
}
System.out.println(temp);
}
}
比如对输入X = {1, 3, 5, 7}, Y = {2, 4, 6, 8}
结果是4。
12.2-3 写出TREE-PREDECESSOR的伪代码
TREE-PREDECESSOR
if x.left != NIL
return TREE-MAXIMUM(x.left)
y = x.p
while y != NIL and y.left == x
x = y
y = y.p
return y
与书上的TREE-SUCCESSOR
相对称.
解释:给定一棵二叉搜索树中的一个结点x,需要按中序遍历查找它的前驱。
一般情况,x的前驱是小于x.key中的最大关键字结点,所以代码前两句if x.left != NIL
在x的左子树中找到max即为它的前驱。
return TREE-MAXIMUM(x.left)
在中序遍历中,如果x左子树为空,y是它的底层祖先,且x==y.left。就像这种情况,所以根据中序遍历,x的前驱为y.p 。代码的后面几行就是在处理这种情况。
12.3-6 当TREE-DELETE中的结点z有两个孩子时,可以选择它的前驱作为y,而不是作为它的后继。如果这样做,对TREE-DELETE应该做哪些什么必要的修改?一些人提出了一个公平的策略,为前驱和后继赋予相等的优先级,这样得到了较好的实验性能。如何对TREE-DELETE进行修改来实现这样一种公平策略?
(1)选择y作为前驱时,在TREE-DELETE
中做孩子情况的修改,伪代码如下:
TREE-DELETE(T, z)
if z.left == NIL //z没有左孩子
TRANSPLANT(T, z, z.right)
else if z.right == NIL //z没有右孩子
TRANSPLANT(T, z, z.left)
//z有两个孩子的情况:
else y = TREE-MAXIMUM(z.left) //找前驱:左子树中最大的 就是z的前驱
if y.p != z //如果y不是z的直接左孩子
TRANSPLANT(T, y, y.left) //1、先用y的左孩子代替y,并成为y父亲的孩子
y.left = z.left
y.left.p = y
//2、再用y代替z,并成为z父亲的一个孩子
TRANSPLANT(T, z, y)
y.right = z.right
y.rignt.p = y
解释:当z只有一个孩子时,与课本处理后继的方式相同,代码前四句就是处理这种情况。
当z有两个孩子时,先找到其前驱y = TREE-MAXIMUM(z.left)
,再分情况处理 y是z的直接左孩子,还是左子树中的结点。
最终都要走的流程是:用前驱y代替z,原来z右边子树移植到y上,这是代码后三行处理的情况。
如果y不是z的左孩子,那么要先用 y.left 代替y,这就是中间部分处理的情况。
(2)若要采用公平策略,只需用抛硬币方法 即用随机数来决定,1 2 两数任取其一来决定是采用前驱还是后继即可。
TREE-DELETE(T, z)
if z.left == NIL
TRANSPLANT(T, z, z.right)
else if z.right == NIL
TRANSPLANT(T, z, z.left)
else if random(1, 2) == 1 //用随机数来决定
y = TREE-MINIMUM(z.right) //选取后继
if y.p != z
TRANSPLANT(T, y, y.right)
y.right = z.right
y.right.p = y
TRANSPLANT(T, z, y)
y.left = z.left
y.left.p = y
else y = TREE-MAXIMUM(z.left) //选取前驱
if y.p != z
TRANSPLANT(T, y, y.left)
y.left = z.left
y.left.p = y
TRANSPLANT(T, z, y)
y.right = z.right
y.rignt.p = y
13.3-2 将关键字 41、38、31、12、19、8 连续地插入一棵初始为空的红黑树之后,试画出该结果树。
解如下:
13.4-3 在练习 13.3-2 中,将关键字 41、38、31、12、19、8 连续插入一棵初始化的空树中,从而得到一棵红黑树。请给出从该树中连续删除关键字 8、12、19、31、38、41 后的红黑树。
解如下: