120 likes | 205 Views
数据结构习题课. 陈家伟. 9.15 试证明:高度为 h 的 2-3 树中叶 子结点 数 目在 2^(h-1) 与 3^(h-1) 之 间。. 在 2-3 树中,每个内 部 结 点(非 叶 子 结 点)有 两个或三个孩子,而且所有叶子都在同 一层上; 一方面,若 某棵 2-3 树 只 包含 2- 结 点 , 则就是一颗满 二叉 树。 高度为 h 的满二叉树 的叶子 结 点数是 2^(h-1) ; 另 一方面 , 若某棵 2-3 树只包 含 3- 结 点,那么第 i 层的 结 点数目是
E N D
数据结构习题课 陈家伟
9.15 试证明:高度为h的2-3树中叶子结点数目在2^(h-1)与3^(h-1)之间。 • 在2-3树中,每个内部结点(非叶子结点)有两个或三个孩子,而且所有叶子都在同一层上; • 一方面,若某棵2-3树只包含2-结点,则就是一颗满二叉树。高度为h的满二叉树的叶子结点数是2^(h-1); • 另一方面,若某棵2-3树只包含3-结点,那么第i层的结点数目是 3^(i-1)。高度为h的“3树”的叶子结点数是3^(h-1); • 高度为h的2-3树中叶子结点数目在2^(h-1)与3^(h-1)之间。
9.16 在含有n个关键码的m阶B-树中进行查找时,最多访问多少个结点? • 定义:一棵m 阶的B-树,或者为空树,或为满足下列特性的m 叉树: ⑴ 树中每个结点至多有m 棵子树; ⑵ 若根结点不是叶子结点,则至少有两棵子树; ⑶ 除根结点之外的所有非终端结点至少有[m/2] 棵子树;(向上) ⑷ 所有的非终端结点中包含以下信息数据: (n,A0,K1,A1,K2,…,Kn,An) Ki(i=1,2,…,n)为关键码,且Ki<Ki+1; Ai 为指向子树根结点的指针(i=0,1,…,n),且指针Ai-1 所指子树中所有结点的关键码均小于Ki (i=1,2,…,n),An 所指子树中所有结点的关键码均大于Kn; n为关键码的个数; ⑸ 所有的叶子结点都出现在同一层次上,并且不带信息;
9.16 在含有n个关键码的m阶B-树中进行查找时,最多访问多少个结点? • 等价于“含有n 个关键码的m 阶B-树,最大高度是多少” • 假设该B-树高为h+1,那么第h+1层有n+1个叶子结点 • (1) 第一层为根,至少一个结点,根至少有两个孩子,因此在第二层至少有两个结点; • (2) 除根和树叶外,其它结点至少有[m/2]个孩子,因此第三层至少有2*[m/2]个结点,在第四层至少有2*[m/2]^2个结点; • (3) 那么在第h+1层至少有2*[m/2]^(h-1)个结点,而h层的结点个数n+1,有: n+1 >= 2*[m/2]^(h-1) h <= log[m/2]{(n+1)/2} + 1
9.39 试写一算法,将一棵二叉排序树分裂成两棵二叉排序树,使得其中一棵树的所有结点的关键字都小于或等于x,另一棵树的任一结点的关键字均大于x。 • 递归 • void BiTree_Split(BiTree&T, BiTree&A, BiTree&B, intx){ if(T->lchild) BiTree_Split(T->lchild, A, B, x); if(T->rchild) BiTree_Split(T->rchild, A, B, x); //分裂左右子树 if(T->data<=x) Insert_Node(A, T); else Insert_Node(B, T); //将元素结点插入合适的树中 }
9.39 试写一算法,将一棵二叉排序树分裂成两棵二叉排序树,使得其中一棵树的所有结点的关键字都小于或等于x,另一棵树的任一结点的关键字均大于x。 • void Insert_Node(Bitree &T, BTNode*S){ if(!T) T=S; //考虑到刚开始分裂时树A和树B为空的情况 else if(S->data > T->data){ if(!T->rchild) T->rchild=S; else Insert_Node(T->rchild,S); } else if(S->data < T->data){ if(!T->lchild) T->lchild=S; else Insert_Node(T->lchild,S); } S->lchild=NULL; S->rchild=NULL; }
9.40 在平衡二叉排序树的每个结点中增设一个lsize域,其值为它的左子树中的结点树加1。试写一时间复杂度为O(logn)的算法,确定树中第k小的结点的位置。 • lsize即是结点从小到大排列的序号 • 高度为logn,递归 • BiNode* Ranking(BiTree T, int k){ if(!T)return NULL; if(T->lsize == k){ return T; else{ if(T->lsize> k) return Ranking(T->lchild, k); else return Ranking(T->rchild, k - T->lsize); } }
9.19 选取哈希函数H(k)=(3k) MOD 11。用开放定址法处理冲突,di=i((7k)MOD10 + 1) (i = 1,2,3,…)。试在0~10的散列地址空间中对关键字序列(22,41,53,46,30,13,01,67)构造哈希表,并求等概率下查找成功时的平均查找长度。 • Hi=(H(key) + di) MOD m,i=1,2,…,k(k<=m-1) • H(22) = 0 • H(41) = 2 • H(53) = 5 • H(46) = 6 • H(30) = 2 —— d1 = 1,3 • H(13) = 6 —— d1 = 2,8 • H(01) = 3 —— d5 = 40,10 • H(67)= 3 —— d2 = 20,1
9.19 选取哈希函数H(k)=(3k) MOD 11。用开放定址法处理冲突,di=i((7k)MOD10 + 1) (i = 1,2,3,…)。试在0~10的散列地址空间中对关键字序列(22,41,53,46,30,13,01,67)构造哈希表,并求等概率下查找成功时的平均查找长度。 哈希表如下: 查找成功时的平均查找长度(比较次数): ASL = 1/8(1+1+1+1+2+2+6+3) = 17/8
10.27 编写一个双向起泡的排序算法。即相邻两遍向相反方向起泡。 • voidBubble_Sort2(int a[], int n){ low = 0; high = n – 1; change = 1; while(low < high && change){ for(i = low; i < high; i++){ if(a[i] > a[i+1]){ swap(a[i], a[i+1]); change=1; } } high--; for(i = high; i > low; i--){ if(a[i] < a[i-1]){ swap(a[i], a[i-1]); change = 1; } } low++; } }
10.31 编写算法,对n个关键字取整数值的记录序列进行整理,以使所有关键字为负值的记录排在关键字为非负值的记录之前,要求:(1)采用顺序存储结构,至多使用一个记录的辅助存储空间;(2)算法的时间复杂度O(n);(3)讨论算法中记录的最大移动次数。 • void Divide(int a[], int n){ low = 0; high = n – 1; pivotkey = a[low]; while(low < high){ while(low < high && a[high] >= 0) high--; a[low] = a[high]; while(low < high && a[low] < 0) low++; a[high] = a[low]; } a[low] = pivotkey; }
10.31 编写算法,对n个关键字取整数值的记录序列进行整理,以使所有关键字为负值的记录排在关键字为非负值的记录之前,要求:(1)采用顺序存储结构,至多使用一个记录的辅助存储空间;(2)算法的时间复杂度O(n);(3)讨论算法中记录的最大移动次数。 • 最大移动次数: 数组前一半是非负数,后一半是负数时,共需要n次移动;