中科院研究生院2010年专业课数据结构复习资料-例题
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Cost( L) W [k ] (depth(W [k ]) in tree L)
k 1 n
j
Cost( R)
k j 1
W [k ] (depth(W [k ]) in tree R)
j k 1 k j 1
而其完成的钢管总重量分别为 W [k ] 和
W [k ] ,因此最后一步焊接代价为:
5.
给出下图所示无向带权图,根据该图完成下列各题: (1) 写出它的邻接矩阵; (2) 按 Prim 算法求其最小生成树,要求按步骤画出生成过程; (3) 利用 Dijkstra 算法求顶点 A 到其他各顶点的最短路径,写出算法执行过 程中各步的状态。
A 2 B 7 C 5 4 1 D 5
8 3 6 G 1 E 6 2 F
参考答案: (1) 邻接矩阵如下: 2 1 8 (2) 步骤如下:
A 1 B D E G F B 2 A 1 D E G F
2 7 5
1 8 7 5 4 5 4 6 3 5 6 2 1 2 6 3 1 6
n
W [ k ]
k 1
j
k j 1
W [k ]
n
因此,最终的焊接总代价为:
Cost(T ) Cost( L) Cost( R) W [k ]
k 1
n
W [ k ] (depth(W [ k ]) in tree L) W [ k ]
k 1 j k 1
A
B
D
G
C
E
F
参考答案:
(1) 邻接矩阵如下: (0 写成∞亦可) 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 1 1 0 0 0 1 0 0 1 0 0 1 0 1 0
7.
8.
现需要将 n 段钢管 a1, a2, ..., an 焊接成一整条钢管,每次可任选两根钢管焊 接在一起,假设钢管 ai 的重量为 W[i](1 ≤ i ≤ n) ,将每次焊接代价计为所 焊的两根钢管的重量之和。 例如, 焊接 5 段钢管, 其重量分别为 5, 2, 6, 11, 3, 若按下图所示二叉树的顺序来焊接这些钢管, 则焊接总代价为: (2+3)+(5+6) +(5+11)+(11+16)=59。
(2) 邻接表如下:
0 1 2 3 4 5 6 A B C D E F G 6 3 4 6 5 6 4 ˄ ˄ ˄ ˄ 1 4 ˄ 2 0 ˄ 5 1 ˄
(3) 强连通分量如下:
A
B
D
G
C
E
F
请设计一个时间复杂度不超过 O(nlogk)的算法,将 k 个已按升序排序的序列 合并成一个升序序列,n 是这 k 个序列元素个数的总和。 (提示:使用小根 堆,重建堆的操作 HEAPIFY 可直接调用,不必给出实现细节) 参考答案: 设 A1, A2, ..., Ak 是 k 个升序序列,先取出各序列的最小元素(第一个元素)建 立一个含 k 个元素的小根堆,下面,在每一步中先取出小根堆的根元素(即剩下 的元素中最小的元素)加入结果序列,如果该元素来自 Aj,则再到 Aj 中取下一 个最小元素加入小根堆并执行堆重建操作(HEAPIFY) ,若 Aj 已无元素,则将 堆尺寸减 1,即将堆尾元素填入堆头并重建堆。当堆为空时即已完成合并。 因为每次输出一个元素均要重建一次堆,而 k 个元素的堆重建操作复杂度为 O(logk),因此整个算法时间复杂度为 O(nlogk),符合要求。 算法伪代码描述如下: Algorithm k-Merge (A1, A2, ... Ak) 1. Build a k-element heap H[1..k] from A1[1], A2[1], ..., Ak[1]. 2. //Let L[j] = p if H[j] = Ap[1]. This is known when we build the heap. 3. for j 1 to k 4. do I[j] 2. //I[j] is the index to the smallest key in the remaining Aj. 5. i 0 6. heapsize k 7. while heapsize 0 do { 8. i i +1 9. C[i] H[1] 10. if (L[1] = p and Ap[I[p]] ) 11. then { 12. H[1] Ap[I[p]] 13. I[p] I[p] + 1 14. } 15. else { 16. H[1] H[heapsize] L[1] L[heapsize] 17. 18. heapsize heapsize - 1 19. } 20. if heapsize > 0 21. then HEAPIFY (H, 1) End.
6)
i=4
i=5
i=6
5 (A, D, C)
7 (A, D, E) 10 (A, D, G, F)
7 (A, D, E) 10 (A, D, G, F) 9 (A, D, E, F)
C {A,D,B,G,C}
E {A,D,B,G,C,E}
F {A,D,B,G,C,E,F}
6.
给出下图所示有向图,根据该图完成下列各题: (1) 求该图的邻接矩阵; (2) 给出该图的邻接表; (3) 求该图的强连通分量。
J H I F A E B L C G K D
4.
试写一算法, 以判断用邻接表方式存储的有向图中是否存在由顶点 vi 到顶点 vj 的路径。
参考答案:
int visited[]=0; int dfs(AdjList g, vi) { vistit[vi]=1; p=g[vi].firstarc; while(p!=NULL) { j=p->adjvex; if(vj==j) { flag=1; return 1; } if(vistited[j]==0) dfs(g, j); p=p->next; } if (!flag) return 0; }
(2). 证明:用反证法证明:不失一般性,设 W[1]为最小重量,假设 W[1]不在二 叉树最底层,W[k]为最底层的一个叶结点,则有 W[k] > W[1],现在交换 W[1] 和 W[k]的位置,得到新的焊接总代价: Cost(new) = Cost(T) – W[1]depth(1) – W[k]depth(k) + W[1]depth(k) + W[k]depth(1) = Cost(T) – (W[1] – W[k])depth(1) + (W[1] – W[k])depth(k) = Cost(T) – (W[1] – W[k])(depth(1) – depth(k)) 因为 W[1]<W[k]且 depth(1)<depth(k),所以(W[1] – W[k])(depth(1) – depth(k))>0, 所以 Cost(new) < Cost(T),这与 T 是最优焊接流程矛盾,故假设不成立,W[1]在 最底层。 (3). 证明:由于最优焊接流程所对应的二叉树为满二叉树,故其最底层至少有两 个叶结点,如果第二轻的钢管不在最底层,则最底层除最轻叶结点外,必有一个 结点重量大于第二轻的结点,交换这两个结点的位置,参照第 2 题的推导可得一 棵总代价更小的树,因此导致矛盾,原结论成立。 (4). 证明: 由 2 和 3 的结论可知最优焊接二叉树最底层的叶结点必包含重量最轻 的两段钢管,假设为 W[1]和 W[2]。若二者有共同父结点,则结论成立;若二者 父结点不同,则必存在一个叶结点 W[x]与最轻的结点 W[1]共有父结点,现交换 W[x]和 W[2]的位置,由于都在最底层,结点深度未变,根据 1 的结论,焊接总 代价也未变,这时 W[1]和 W[2]共有父结点,且焊接流程是一种最优焊接流程, 因此结论成立。 (5). 根据上述讨论可知, 每次焊接只要选取剩余钢管中最轻的两段焊接在一起即 可保证焊接总代价最小,因此可设计贪心算法如下: Least-Cost-Weld(W[1..n], c) 1. if n = 1 2. then return (c =0) 3. Construct a min-heap H on W[1..n] 4. for i 1 to n-1 5. do { x extract-min (H)
k 1
n
(2) 若称焊接总代价最小的焊接流程为最优焊接流程,证明在最优焊接流程 所对应的满二叉树中,最底层的叶结点中必有一结点代表重量最轻的那 段钢管。 (3) 证明在最优焊接流程所对应的满二叉树中,重量第二轻的钢管所对应的 叶结点也在二叉树最底层的叶结点中。 (4) 证明必有一种最优焊接流程在第一步焊接时将最轻的两段钢管焊接在一 起。 (5) 试设计一个贪心算法找出一种最优焊接流程并分析算法的时间复杂度。
wenku.baidu.com
1)
C A 2 B 1 D E C 3 G F
2)
C A 2 B 1 D 3 G 1 E C F
3)
4)
A 2 B 1 D 3 G 1 E C C 2 F B 4 2
A 1 D 3 G 1 E 2 F
5) (3) 执行过程如下表所示:
终点 B C D E F G Vmin S i=1 2 (A, B) ∞ 1 (A, D) ∞ ∞ 8 (A, G) D {A,D} 7 (A, D, E) ∞ 4 (A, D, G) B {A,D,B} 7 (A, D, E) ∞ 4 (A, D, G) G {A,D,B,G} i=2 2 (A, B) 5 (A, D, C) 5 (A, D, C) i=3
参考答案: (1). 证明:使用归纳法证明,对二叉树高度 h 归纳: h=0 或 h=1 时结论显然成立; 假设对于任意高度小于或等于 h 的二叉树结论成立, 则对于高度为 h+1 的二叉树 T, 假设其左子树和右子树为 L 和 R, 分别包含叶结点 W[1]~W[j]和 W[j+1]~W[n], 则根据假设, 左子树和右子树的焊接总代价 而 T 的根结点代表了最后一步焊接。 分别为:
(27) (11) 6 2 (5) 5 3
(16) 11
显然,每一种焊接流程都可以用如上图所示的一棵满二叉树来表示。根据上面所 述完成下列各题: (1) 证明:任意给定一棵表示焊接流程的含有 n 个叶结点的满二叉树,其焊 接总代价可由下式计算:
Cost(T ) W [k ] depth(W [k ])
n
W [ k ] (depth(W [ k ]) in tree T )
k 1 n
k j 1
W [k ] (depth(W [k ]) in tree T )
n
W [k ] (depth(W [k ]) in tree T )
k 1
符合提给表达式,因此对于高度为 h+1 的二叉树,结论也成立。
2.
画出和下列已知访问序列对应的树: 树的先根次序访问序列为:KIMCBDNFHJEALG; 树的后根次序访问序列为:MCIBNHFJDLAGEK。 参考答案:
K I M C B N D F H J A L E G
3.
画出和下列已知访问序列对应的森林: 森林的先序次序访问序列为:JHEFIABLGCKD; 森林的中序次序访问序列为:HJIAFBLECDKG。 参考答案:
1. 试利用栈的基本操作写出二叉树后序遍历的非递归算法。 参考答案: 除了记录每次递归根结点的栈之外,还需要一个记录当前结点遍历状态的栈,如 果处于左子树遍历,状态为 0,否则状态变为 1。
Status PostOrderTraverse(BiTree T, Status (*Visit)(ElemType e)) { // 采用二叉链表存储结构,Visit 是对数据元素操作的应用函数 InitStack(Sroot); InitStack(Stag); p = T; while (p || !StackEmpty(Sroot)) { if (p) { Push(Sroot, p); Push(Stag, 0); p = p‐>lchild; } else { Pop(Stag, tag); if (tag == 0) { GetTop(Sroot, p); Push(Stag, 1); p = p‐>rchild; } else { Pop(Sroot, p); if (!Visit(p)) return ERROR; p = NULL; } } } return OK; }
j
j
k j 1
W [k ] (depth(W [k ]) in tree R)
n
k j 1
W [ k ]
n
W [ k ] (depth(W [k ]) in tree L 1)
k 1 j
k j 1
W [k ] (depth(W [k ]) in tree R 1)