习题讲解
张源 [email protected]张仁涛 [email protected]
Exercises 1
Write a recursive method that returns thenumber of 1’s in the binary representation of N.Use the fact that is equal to the number of 1’s inthe representation of N/2, plus 1, if N is odd.
数字N二进制中1的个数
设N的二进制表示有n位,即求n位二进制数中1的 个数,即求前n-1位二进制数中1的个数与最后一 位1的个数的总和。
边界条件:(n==0)
递归返回段:返回n
递归前进段:count(n/2)+n%2;
代码
public int count(int n) { if(n==0) {
return 0; }
else {
return n%2 +count(n/2);
} }
条件n==1不用作为边界条件,每一次会多一次 判断。
不必讨论n的奇偶性。
Exercises 2
Write the routines wise the following declarations:
public void permute( String str );
private void permute( char [ ] str, int low, int high )
The first routine is a driver that calls the second and prints all the permutations of the characters in String str. If str is“abc”, then the strings that are output are abc, acb, bac, bca, cab,and cba. Use recursion for the second routine.
全排列
n个字母的全排列,一个一个地进行挑选
边界条件:只剩一个字母(low==high)
递归返回段:输出得到的一个排列
abc
abc bac cba
递归前进段:对剩下的n-1个字母进行全排列
abc acb
abc acb
// low和high标记进行全排列的字母的范围public void perm(char[] str , int low, int high) {
if (low==high) { for (char c : str)
cout << c; cout << endl;
} else {
for (int i=low; i<=high; i++) {
swap(str, low, i); permute(str, low+1, high); swap(str, low, i);
} }
}
交换函数
//str是引用传递(passed by reference) void swap(char[] str, int i, int j) {
char temp=str[i]; str[i]=str[j]; str[j]=temp;
}
Exercises 3
已知a[n]为整型数组,试写出实现下列运算的递归算法。1)求数组a中的最大整数。
2)求n个整数的平均值
数组中最大整数(1)
将数组中前n-1个数的最大值与第n个数比
较,返回较大的。
边界条件:(n==1)。
递归返回段:返回a[0]。
递归前进段:将剩下的n个数的前n-1个数的最 大值与第n个数进行比较,返回较大的。
public int findMax(int[] a, int n) { //n表示第n个元素,对应数组a[n-1]
if(n==1){ return a [0];
} else {
int temp = findMax(a, n-1);
return temp > a[n-1] ? temp : a[n-1];
} }
不好的编程方式
else {
if( a[n-1] < findMax(a, n-1) )
return a[n-1] ; else
}
return findMax(a, n-1);
数组中最大整数(2)
分别求出数组前半段和后半段的最大值,
返回其中较大的。
边界条件:(low==high)。
递归返回段:返回a[low]。
递归前进段:计算剩下的n个数的前半段和后 半段的最大值,返回其中较大的。
// 初始值 low=0, high=a.length int max(int [] a, int low, int high) {
if(low==high) return a[low];
else {
int x = max(a, low, (low+high)/2);
int y = max(a, (low+high)/2+1, high); return x > y ? x : y;
} }
n个整数的平均值(1)
求出前n-1个数的和,再求它跟第n个数的
平均值。
边界条件:(n==1)。
递归返回段:返回a[0]。
递归前进段:计算剩下的n个数的前n-1个数的 和,再求它跟第n个数的平均值。
public double getAverage(int[] a, int n) { // n表示数组的第n个元素
if (n==1) return a[0];
else
return (getAverage(a, n-1)*(n-1) + a[n-1]) / n;
}
n个整数的平均值(2) 先求出n个数的和,再除以n
public double getAverage(int[] a, int n) { // n表示数组的第n个元素
return getSum( a, n )/n; }
public double getSum( int[] a, int n ){
return getSum( a, n-1 ) + a[n-1]; }
Exercises 4
Write a recursive method that calculates and returns the length of a linked list.
计算和返回链表长度publicintlength(ListNodea) //计算方法{
if(a==null) return 0;
else return 1 + length(a.next);
}
classListNode //节点类{
Object content=null;
ListNode next=null;}
Exercises 5
Check recursively if the following objects are palindromes:
a. a word
b. a sentence (ignoring blanks, lower and uppercasedifferences, and punctuation marks so that “Madam, I’m Adam” is accepted as a palindrome)
检测回文
a) 一个单词
b) 一个句子(忽略空格,大小写,标点, 例如“Madam,I’m Adam”是一个回文)
a) 检测回文单词
比较头尾两个字符,相同则向中间聚拢比较,不相同则返回false。
边界条件和递归返回段:
要比较的子字符窜为空,返回true
递归前进段:截取当前字符串从位置1到位置length-1的子字符串,
返回其回文性。
public static boolean palindrome0(String word, int low, int high) { if (low > high)
return true;
if (word.charAt(low) == word.charAt(high)
|| Math.abs(word.charAt(low) - word.charAt(high)) == 32)
return palindrome(word, low+1, high-1); else
return false; }
b) 检测回文句子 在递归过程中去除不符合要求的字符
public static boolean palindrome(String word, int low, int high) { if (low > high)
return true;
while (!Character.isLetter(word.charAt(low)))
low++;
while (!Character.isLetter(word.charAt(high)))
high--;
if (word.charAt(low) == word.charAt(high)
|| Math.abs(word.charAt(low) - word.charAt(high)) == 32) return palindrome(word, low+1, high-1);
else
return false;
}
另一种解法
首先去除不符合要求的字符,然后检测其回文性
public static boolean sentence(String word) { String s1 = word.toLowerCase();
String s2 = "";
for(int i = 0; i < word.length(); i++)
if (s1.charAt(i) >= 'a' && s1.charAt(i) <= 'z') s2 += s1.charAt(i);
return palindrome(s2, 0, s2.length()-1); }
计算复杂度的方法 for( i=0; i for( j=i; j Chapter 2 2nn 2 n1n1 1i0ji 错误的方法 for( i=0; i {...} 外层n次循环 内层O(n) 所以是O(n2) Exercise 1 Find the complexity of the function used to find the kth smallest integer in an unordered array of integers. int selectkth ( int a[], int k, int n){ int i, j, mini, temp; mini = i; if ( a[j] < a[mini]) mini = j; tmp = a[i]; a[i] = a[mini]; a[mini] = tmp; returna[k-1]; 1 + 1+3 =?? − 2 +2??=0 ?=?+1 } Exercise 2 Find the computational complexity for the following four loops: c. for (cnt3=0, i =1; i<=n; i*=2) for (j=1; j<=n; j++) cnt3++; d. for (cnt4=0, i=1; i<=n; i*=2) for (j=1; j<=i; j++) cnt4++; ? 1 t = ???h. ?????(log2 ?) 20+21+...+2?=2?+1 −1=?(?) ???h.?????(log2?)+1 ∗ 1=? ∗ log2?+?=?(?∗ln?) Exercise 3 For each of the following two program fragments: Give an analysis of the running time(Big-Oh will do) sum = 0; for( j = 0; j
sum++; sum = 0; for( i = 1; i < n; i++ ) for( j = 0; j < i*i; j++ ) if( j % i == 0 ) sum++; ?−1 ? 2 −1 ?−1 ?−1 ? 2 −1 ?−1 ?4 − ?2 ?=0 ?=0 ?=0 ?−1 ?−1 ?=0 ?=0 2?−1 ?=0 1 = ? = 2 ? ?−1 −1 5= ?(? ) (1+1+...+ 1)= ?=1 ?=0 ?=0 ?=0 ?−1 (? + 2? + ⋯ + ?(? − 1)) = ?=1 ?−1 ?3 − ?2 4 Exercise 4 4. 设n为正整数,分析下列各程序段中加下划线的语句的执行次数。1) for (int i = 1; i <= n; i++) for (int j = 1; j<=n; j++) { c[i][j] = 0.0; for ( int k = 1; k <= n; k++) c[i][j] = c[i][j]+a[i][k]*b[k][j]; } for (int i = 1; i <= n; i++) for (int j = 1; j <= i; j++) for (int k = 1; k <= j; k++) x = x+y; 3) int x = 91; int y = 100; while(y>0) { if(x>100) { x -= 10; y--; } // (1) else x++; // (2) } ??? ?=1 ?=1 ?=1 ? ? ? ?(? + 1)(? + 2) 6 1 = 12+22+32+....+n2=n(n+1)(2n+1)/6 a:(2)每执行10次,(1)执行1次,y--1次b:y--执行100次so:(1)执行100次,(2)执行100*10次 要有注释 要有过程 字体整洁 注意 数据结构与算法分析 第二次作业 张仁涛 [email protected]张 源 [email protected] 作业注意事项 不要抄袭 作业不完整,遗漏 链表不要直接使用java自带的LinkedList 代码写清楚,不要直接用自然语言描述 下周检查上机题(检查前自己看看,不要提问 的时候说不出来) 矩阵部分完成的同学,这次可以不交矩阵部分 3.1 Swap two adjacent elements by adjusting only the links ( and not the data ) using: a. Singly linked lists. b. Doubly linked lists. 3.1 通过只调整链来交换两个相邻的元素,使用a. 单链表 b. 双链表 单链表 1 a.next = b.next 3 a.next.next = b abc2d 双链表 1 2 3 6 4a5bcd 1. a.right = b.right; 4. b.right.left = b; 5. a.right.left = a; 6. b.left = a.right; 注意 赋值某个链后,原链已经不存在,不能使用原 链来获得节点 修改链表不完全,遗漏 只画图,没代码 3.2 Given two sorted lists L1 and L2,write a procedure 3.2 给定两个已排序的表L1和L2,只使用基本的链表操作编 写计算L1∩L2的过程。 分析 假设链表节点已按照节点值从小到大排列。 L1当前节点值=L2当前节点值,把该节点加入L,同 时L1、L2前进 L1当前节点值 返回L。 代码 public LinkedList intersection (LinkedList L1,LinkedList L2){ LinkedListItr itr1 = L1.first(); while(!itr1.isPastEnd() && !itr2.isPastEnd()){ if(itr1.retrive() == itr2.retrive()){ L.insert(itr1.current,itr); itr1.advance(); itr2.advance(); } else if(itr1.retrive() < itr2.retrive()) itr1.advance(); //当前节点是否为空//若两个链表当前节点值相等 else } } return L; } itr2.advance(); 注意 如果不创建新链表,直接在L1上修改,p3指向已选择出 的结果的最后一个节点。那么while循环结束后,没有把p3.next=null。 直接在原链表上修改,不好 结果链表最好也是排序好的 有的同学,运用两层for循环,分别对两个链表进行遍历itr.advanced()只能执行一次 有的同学,直接运用LinkedList,通过list的size()方法进 行两层遍历 3.3 Given two sorted lists, L1 and L2, write a procedure 3.3 给定两个已排序的表L1和L2,只使用基本的链表操作编 写计算L1∪L2的过程。 分析 假设链表节点按照节点值从小到大排列。 新建链表L,存放L1∪L2的结果,故返回类型为链表。 遍历L1和L2, 比较L1、L2当前节点值 L1当前节点值=L2当前节点值,把该节点加入L ,L1、L2前进 L1当前节点值 L1当前节点值>L2当前节点值,把L2当前节点加入L , L2前进 若L1为空,把L2剩余节点加入L,停止遍历 若L2为空,把L1剩余节点加入L,停止遍历 返回L。 代码 public LinkedList intersection (LinkedList L1,LinkedList L2){ LinkedListItr itr1 = L1.first(); while(!itr1.isPastEnd() && !itr2.isPastEnd()){ //当前节点是否为空if(itr1.retrive() == itr2.retrive()){ //若两个链表当前节点值相等 L.insert(itr1.current,itr); itr1.advance(); itr2.advance(); } L.insert(itr1.current,itr); } } } L.insert(itr2.current,itr); itr2.advance(); itr1.advance(); else{ //如果L1没有结束,将L1剩余元素添加到L中for(;!itr1.isPastEnd();itr1.advance()) { L.insert(itr1.current,itr); } //如果L2没有结束,将L2剩余元素添加到L中for(;!itr2.isPastEnd();itr2.advance()) { L.insert(itr2.current,itr); } return L; } 注意 使用两个for循环嵌套 while循环结束后,误以为计算已经完成,没有 把L1或L2剩余的节点链入结果链表 3.4 Write a nonrecursive method to reverse a singly linked List in O(N) time. 3.4 编写一个非递归方法以O(N)的时间复杂度反转单链表。 分析 做法1:用堆栈来保存链表的遍历,用pop倒序输 出,每倒序输出一个就构造新链表的一个结点。 做法2:在原链表的上用指针操作来进行链表的 扭转。 方法2 对于第一个节点firstNode 将firstNode.next设为null 对于其他节点 最后对于头指针 代码 public void reverse() { if (p1 == null) return; // node.next设为前一个node ,然后指针前移一个位置 while (p3 != null) { p2.next = p1; p1 = p2; } } 注意 未判断p1和p2为空情况 while(n.hasNext()){ n.next = before; before = before.next; n = n.next; } 统考题 若元素a,b,c,d,e,f依次进栈,允许进栈、退栈操作交替进 行。但不允许连续三次进行退栈工作,则不可能得到的 出栈序列是( ) A:dcebfa B:cbdaef C:bcaefd D:afedcb 入栈顺序:a, b, c, d, e, f, g 出栈顺序: a, f, e, d, c, b f e d c ab a f e d c b 统考题 1、为解决计算机主机与打印机之间速度不匹配问题, 通常 设置一个打印数据缓冲区,主机将要输出的数据依次写 入该缓冲区, 而打印机则依次从该缓冲区中取出数据.该缓冲区的逻辑结构应该是( ) A. 栈 B. 队列 C. 树 D. 图 A 栈是后进先出 B是先进先出,FIFO,符合题目条件 CD都有一定的时间复杂度,新建插入搜索删除都需要一 定的时间开销,而这些开销对于问题的解决是没有实 际意义的。 所以最后答案选择B 统考题 设栈S和队列Q 的初始状态为空, 元素a,b,c,d,e,f,g 依次进入栈S. 若每个元素出栈后立 即进入队列Q, 且7个元素出队的顺序是b,d,c,f,e,a,g , 则栈S的容量至少是 A.1 B.2 C.3 D.4 a,b,c,d,e,f,g 依次 进入栈S b,d,c,f,e,a,g f d c e b g a top 2 Suppose that a singly list is implemented with both a header and tail node. Describe contant-time algorithms to a. Insert item x before position p ( given by an iterator ). b. Remove the item stored at position p ( given by an iterator ) head P tail A B C head P tail A B B C head P tail A X B C 代码 public void insert(LinkedListItr itr, Object x){ ListNode p= itr.current; if(p!=head) { /*在p后插入一新节点*/ ListNode addnode=new ListNode(p.element, p.next); p.next=addnode; p.element=x;/*p指向节点的元素值用x替 换*/ } } 删除算法: 2. 否则,用P下一节点中元素的值替换P节点中的值,再删除P的下一节点 P A B C head P tail A B head P tail A B head P tail A B head P tail A C head P tail C C A C 代码 Public void remove(LinkedListItr itr){ ListNode p=itr.current; if(p!=head && p!=tail){ if(p.next==tail){/*如果p是最后一个节点*/ tail=p; tail.next=null; } else{ p.element=p.next.element; } } p.next=p.next.next; } 3 假设以数组Q[m]存放循环队列中的元素,同时以rear和length 分别指示环形队列中的队尾位置和队列中所 含元素的个数: 1)求队列中第一个元素的实际位置。 2)给出该循环队列的队空条件和队满条件,并写出 相应的插入(enqueue)和删除(dlqueue)元素的操作。 情况一: front=rear-length+1 front rear 情况二: front=rear-length+1+mfront’ rear front 合并: front=(rear-length+1+m)%m ....... ....... 队空情况: length==0队满情况: length==m public void enqueue(Object x) throws Overflow{ /*入队*/ if(isFull()){ throws new Overflow(); } else{ } } length++; public Object dequeue() throws Underflow{ /*出队*/ if(isEmpty()){ throws new Underflow(); } else{ } } length--; 关于rear==0,length==0的问题 front rear o1 rear==0,length==1 rear==0,length==0出始状态呢? rear= -1, front= 0 O1出队 rear front 注意 在实现出队的操作时,有同学使用rear--, 注意rear是队尾,队列出队操作是对队首元素进行操 作, 所以使用length--,或者front++是等价的,因为满足关 系,front=(rear-length+1+m)%m 习题讲解3 Chapter3.1 2010年全国考研统考题 设将n(n,1)个整数存放到一维数组R中,试设 计一个在时间和空间两方面尽可能有效的算法, 将R中保有的序列循环左移P(0
(1)给出算法的基本设计思想。 (3)说明你所设计算法的时间复杂度和空间 复杂度 设计思想 可以将这个问题看做是把数组ab转换成数 组ba(a代表数组的前p个元素,b代表数组 中余下的n-p个元素)。先将a逆置得到a-1b, 再将b逆置得到a-1b-1,最后将整个a-1b-1逆 置得到(a-1b-1)-1=ba。 或先逆置ab,得到b-1a-1,再分别逆置b-1和a-1,得到ba。 void Converse(int R[],int n,int p){ Reverse(R,0,p-1); } void Reverse(int R[],int from,int to) { int i,temp; for(i = 0; i < (to-from+1)/2; i++){ temp = R[from+i]; R[from+i] = R[to-i]; R[to-i] = temp; }} } 时间复杂度:O(n) 空间复杂度:O(1) 另一种方法 算法思想:创建大小为p的辅助数组S,将R中 前p个整数依次暂存在S中,同时将R中后n-p个 整数左移,然后将S中暂存的p个数依次放回到R中的后续单元。 时间复杂度:O(n) 空间复杂度:O(p) 数组与矩阵 设有一个n*n的对称矩阵A,如下图(a)所示。 为了节约存储,可以只存对角线及对角线 以上的元素,或者只存对角线或对角线以 下的元素。前者称为上三角矩阵,后者称 为下三角矩阵。我们把它们按行存放于一 个一维数组B中,如图(b)和图(c)所示。并 称之为对称矩阵A的压缩存储方式。试问: 1)存放对称矩阵A上三角部分或下三角部 分的一维数组B有多少元素? 1+2+......+n=n(n+1)/2 先来看第(3)问 3)若在一维数组B中从0号位置开始存放, 则如图(a)所示的对称矩阵中的任一元素aij在只存下三角部分的情况下*(图(c))应存于 一维数组的什么下标位置?给出计算公式。 前i-1行:1+2+......+(i-1)=i(i-1)/2第i行:j ......... 下标:i(i-1)/2+j-1 a11 an1 an2 ... ann(c) aa21 22 2)若在一维数组B中从0号位置开始存放, 则如图(a)所示的对称矩阵中的任一元素aij在只存上三角部分的情形下(图(b))应存于 一维数组的什么下标位置?给出计算公式。 直接交换第(3)问的i与j 下标:j(j-1)/2+i-1 2009年统考题 3 给定二叉树如下图所示. 设N 代表二叉树的 根, L代表二叉树的左子树, R代表根结点的 右子树. 若遍历后的结点序列为 3, 1, 7, 5, 6, 2, 4, 则其遍历方式是(右3中1) A. LRN B. NRL C. RLN D. RNL 2009年统考题 4 已知一棵完全二叉树的第6 层(设根为第1层)有8个叶结点, 则该完全二叉树的结点个数 最多是 D. 119 A. 39 B. 52 24 8 24*2 C. 111 level 1 20level 2 21 level 6 25 26 −1+ 25 −8 ∗2=111 ... ... 2009年统考题 5 结点的父结点, 则在原来的森林中, u 和v 可能具有的关系是: 1)父子关系 2)兄弟关系 3) u 的父结点与v 的父结点是兄弟关系 A. 2) B. 1)和2) C. 1)和3) D. 1), 2)和3)1 2 3 2010年全国考研题 3 下列线索二叉树中(用虚线表示线索), 符合后序线索树定义的是(D) PostOrder:dbca 5 在一棵度为4的树T中,若有20个度为4的结 点,10个度为3的结点,1个度为2的结点,10个度为1的结点,则树T的叶节点个数是: A:41 B:82 C:113 D:122 节点数 = 边数 + 1 6 对n(n大于等于2)个权值均不相同的字符构 成哈夫曼树,关于该树的叙述中,错误的 是() A:该树一定是一棵完全二叉树 D:树中任一非叶结点的权值一定不小于下一 层任一结点的权值 1.给出如下各表达式的二叉树 方法一:中缀表达式→后缀表达式→二叉树 编程时使用 (a+b)/(c-d*e)+e+g*h/a + +/ /e*a + abc* de gh - -x-y*z+(a+b+c/d*e) + -+ -*+* xyzab/e x是-的右节点,可 以按0-x来理解 cd ((a+b)>(c-d))||a &&的优先级比||高 || > +-< || >xyyz abcdaf < 2. 如果一棵树有n1个度为1的结点,有n2个 度为2的结点,......,nm个度为m的结点, 试问有多少个度为0的结点?写出推导过程。 节点数 = 边数 + 1 ?0=?2+2?3+3?4+...+ ?−1??+1 3.分别找出满足以下条件的所有二 叉树 1)二叉树的前序序列与中序序列相同NLR===LNR So:所有节点都没有左节点、只有根节点、空树 LNR===LRN So:所有节点都没有右节点、只有根节点、空树 3)二叉树的前序序列与后序序列相同NLR===LRN So:只有根节点、空树 4.若用二叉链表作为二叉树的存储 表示,试对以下问题编写递归算法。 1)统计二叉树中叶结点的个数。 public static int leafNum(BinaryNode root) {if (root == null) return 0; return 1; } 2)以二叉树为参数,交换每个结点的左子女和右 子女 public static void switchLR(BinaryNode root) {if (root == null) return; } 5.已知先序ABECDFGHIJ,中序EBCDAFHIGJ,试画出二叉树。 ABECDFGHIJ EBCDAFHIGJ A BECD EBCD FGHIJ FHIGJ B F EECDCD GHIJHIGJEC G DDHIHIJJ DHJ III 6.编写一个Java函数,输入后缀表达式,构造其二 叉树表示。设每个操作符有一个或两个操作数。 遍历表达式 若为操作数,将其构造成节点后入栈; 若为一元操作符,弹出一个节点作为操作符的 右child构造新节点,将新节点入栈; 若为二元操作数,弹出两个节点分别作为操作 符的右左child构造新的节点,将新节点入栈。 public static BinaryNode makeTreeFromPostfixExpression(String expression) { Stack stack = new Stack (); expression = expression.replaceAll(" ", ""); for (int i = 0; i < expression.length(); ++i) { char ch = expression.charAt(i); switch (ch) { case '+': case '-': case '*': case '/': case '^': BinaryNode right = (BinaryNode) stack.pop(); BinaryNode left = (BinaryNode) stack.pop(); stack.push(new BinaryNode(ch, left, right)); break; BinaryNode node = (BinaryNode) stack.pop(); stack.push(new BinaryNode(ch, null, node)); break; stack.push(new BinaryNode(ch, null, null)); break; 7.给定权值{15,03,14,02,06,09,16,17},构造相应的霍 夫曼树,并计算它的带权外路径长度。 2 3 6 9 14 15 16 17 2 + 3 -> 5 5 6 9 14 15 16 17 335 + 6 -> 11 82 49 9 11 14 15 16 17 9 + 11 -> 20 14 15 16 17 20 14 + 15 -> 29 16 17 20 29 16 + 17 -> 33 20 29 33 16 17 20 9 11 29 14 15 56 20 + 29 -> 49 33 49 23 8.c1,c2,c3,c4,c5,c6,c7,c8这八个字母的出现频率分别 {5,25,3,6,10,11,36,4}为这八个字母设计不等长的 Huffman编码,并给出该电文的总码数。 3 4 5 6 10 11 25 36 3 + 4 -> 7 5 + 6 -> 11 7 10 11 11 25 36 7 + 10 -> 17 17 0 39 100 01 61101 22 25 36 11 11 17 25 36 11 + 11 -> 22 17 22 25 36 01 01 c2 c7 17 + 22 -> 39 0 1 c5 c6 0 1253639 34 56 25+ 36-> 61 39 61 c3 c8 c1 c4 c1:0110 c2:10 c3:0010 c4:0111 c5:000 c6:010 c7:11 c8:0011总码数即带权外路径长度:4*5 + 2*25 + 4*3 + 4*6 + 3*10 + 3*11 + 2*36 + 4*4 = 257 数据结构与算法分析第四次作业 张仁涛 [email protected]张 源 [email protected] 统考题: A. B. C. D. 统考题: A. 根结点最多有m棵子树 Exercise 1 Show the result of inserting 3, 1, 4, 6, 9, 2, 5, 7 into an initially empty binary search tree. Show the result of deleting the root 3 1 3 33 3 1 14 14 9 333 141414 26262695959 7 P is a leaf 3 14 26 5 9 7 对于第三种情况: 1.可以归结为第一种情况(也可能为第二种情况),即 用被删结点的左子树的最大值 2 来替换(最后归结为 删除叶子结点2) 或用被删结点的右子树的最小值 4 来替换(最后归结 为第二种情况的删除4) 2.也可以归结为第二种情况,即使得被删结点只有一 个分支,如下, 把被删结点的左子树挂到右子树上; 或把被删结点的右子树挂到左子树上 4 2 14 6 59 7 1 6 259 7 方案一 方案二 Exercise 2 写一递归函数实现在带索引的二叉搜索树(IndexBST)中查找第k个小的元素 对于任一节点node,leftsize=左子树中元素个数+1 leftSize left element right 查找以node为根节点的二叉搜索树中第k个小的元素 If k==n.leftsize,则查找目标为node本身 Public BinaryNode findkth(BinaryNode t,int k) { else } Exercise 3 对一棵空的AVL树,分别画出插入关键码为{ 16,3,7,11,9,28,18,14,15}后的AVL树 16 16 16 7 左双 33 7 7 16 11 9 3 16 7 3 11 3 16 右单 7 3 11 7 3 9 28 11 7 39 1111 左单 7 16 3 16 11 28 16 28 18 右双 3 9 16 11 3 9 16 14 11 28 14 28 3 9 16 左双 11 3 9 15 28 14 16 Exercise 4 写一个程序判断一个二叉树是不是二叉搜索树 二叉搜索树必须满足: 左子树(如果有)中所有节点都小于该节点 右子树(如果有)中所有节点都大于该节点 左子树(如果有)也是二叉搜索树右子树(如果有)也是二叉搜索树 方法1:检验左子树的最大值和右子树的最小 值 Public boolean isBST(Node n) { return false; return false; } 方法1 Public Node max (Node n) { } Public Node min (Node n) { } 方法2:中序排列 Public boolean isBST(Node n) {If(n==null) return true; if(l.get(i)>=l.get(j)) return false; } Return true;} 方法2 Public List inOrderList(Node n) {List l = new ArrayList(); inOrderList(n, l); } Public void inOrderList(Node n, List l) {If(n==null) return; inOrderList(n.left, l); l.add(n.element); inOrderList(n.right, l); } 5. 设有序顺序表中的元素依次为017,094,154,170,275,503,509,512,553,612,677, 765,897,908. 试画出对其进行二分法搜索时的判定 树, 并计算搜索成功的平均搜索长度。 分析:共14个数,所以共log2(14+1)向上取整为4层 建树方法:从根节点起,每次取中间位置的数作为节 点内容,若中间有两个则取后一个。 017,094,154,170,275,503,509,512,553,612,677, 765,897,908 512 765 170084 503 094 908 275 509 553 677 897 612 017 平均搜索长度: l=(1+2*2+3*4+4*7)/14=45/14 6.在一棵表示有序集S 的二叉搜索树中, 任意一条从 根到叶结点的路径将S分为三部分: 在该结点左边结 点中的元素组成集合S1; 在该路径上的结点中的元素 组成集合S2; 在该路径右边结点中的元素组成集合S3, S=S1US2US3. 若对于任意的a S1, b S2, c S3,是否总有a<=b<=c? 为什么? 不一定。 如下图,取路径7->9->12->11,令a=8,b=7. 7 5 9 4 8 12 7. 将关键码DEC, FEB, NOV, OCT, JUL, SEP, AUG, APR, MAR, MAY, JUN, JAN 依次插入到 一棵初始为空的AVL 树中, 画出每插入一个关键码 后的AVL 树, 并标明平衡旋转的类型. DEC, FEB, NOV, OCT, JUL, SEP, AUG, APR, MAR, MAY, JUN, JAN DEC DEC DEC FEB FEB FEB DEC 左单 NOV FEB DEC NOV FEB DEC NOV JUL NOV OCT OCT SEP, AUG, FEB DEC NOV SEP NOV NOV JUL OCT 左单旋转 DEC JUL SEP DEC AUG JUL SEP APR, MAR, MAY, JUN, JAN NOV NOV FEB AUG APR DEC OCT SEP DEC AUG APR JUL SEP JUL MAR MAY, JUN, JAN NOV FEB AUG APR DEC OCT SEP APR MAY NOV FEB OCT SEP 左单旋转 JUL AUG DEC MAR JUN, JAN NOV FEB OCT 左双旋转 MAR FEB AUG DEC MAR SEP NOV SEP APR JUL MAY APR JUN JUL MAY JUN DEC JAN MAR FEB NOV APR AUG DEC JUL MAY JUN SEP JAN 按月份的结果 JUL MAR OCT NOV DEC FEB MAY SEP JAN Exercise 8 分别 delete 50 ,40 in the following 3阶B-树.50 60 80 20 40 55 70 30 95 Delete 50找出50的左子树的最大值(40)或者右子数的最小 值(55)来代替。 55 55 30 30 60 70 95 Delete 4050 60 80 20 5570 30 95 20 30 50 55 70 95 50 20 30 60 70 95 55 10. 分别画出插入65, 15, 40, 30后的3阶B-树。55 45 80 90 55 插入65 45 80 90 55 55 80 65 25 35 50 45 6580 90 45 90 5 插入15 45 65 90 25355060708595 5580 25 45 90 65 90 55 80 45 65 15 25 35 50 60 70 插入40 25 45 65 90 55 80 25 45 15 3540 50 60 65 90 70 插入30 25 45 65 90 55 80 25 35 45 70 65 90 55 80 25 45 15 30 40 50 60 70 65 90 35 55 80 25 45 65 90 15 30 40 50 60 70 85 95 55 35 25 45 80 65 90 15 30 40 50 60 70 8. 对于一个高度为h 的AVL 树, 其最少结点数是多少?反之, 对于一个有n 个结点的AVL 树, 其最大高度 是多少? 最小高度是多少? 设T h 为一棵高度为h,且结点个数最少的平衡二叉树。 假设右子树高度为h-1,因结点个数最少,左子树高度只能是h-2这两棵左子树,右子树高度分别为h-2, h-1,也一定是结点数 最少的: h - 2{ } h - 1 h h = 0 h = 1 h =2 h = 3 T h = 40 T1 T2 n = 1 n = 2 n = 4 T3 n = 7 T4 n = 12 以上五棵平衡二叉树,又称为Fibonacci树。 也可以这样说一棵高度为h的树,其右子树高度为h-1的 Fibonacci树,左子树是高度为h-2的Fibonacci树,即 Th - 2 Th - 1 假设N h表示一棵高度为h的Fibonacci树的结点个数,则N h =N h - 1 + N h - 2 + 1 N 0 = 1 , N 1 = 2 , N 2 = 4 , N 3 = 7 , N4 = 12 , . . . Nh + 1满足费波那契数的定义,并且Nh+ 1= Fh + 3f0 f1 f2 f3 f4 f5 f6 ... 0 1 1 2 3 5 8 ...费波那契数Fi 满足下列公式 11+√5i 11-√5i Fi =——(———)-——(———) √5 2 √5 2 1-√52 ∵ 1-√5 1 2 √5 i 1+√52 h +3 1√5 i 2 1+√5 h +3 1n+1≥Nh+1=——(———) +O(1) √5 对于一个有N 个结点的AVL 树, 其最大高 度是多少? 最小高度是多少? 个数最少的, 1 1+√5 √5 2 h +3 + O( 1 ) 1 i 3 1+√5 2 2log —— 2 2 2 这就是h的最大值; 至于h的最小值,是一颗完全二叉树的时候,高度最小,有 h +1 1.给定输入 { 4371,1323,6173,4199,4344,9679,1989 } 哈希函数为 h(x) = x mod 10, 指出下列结果: a.分离链接散列表; b.使用线性探测的开放定址散列表; c.使用平方探测的开放定址散列表; d.第二个散列函数为h2(x)=7-(x mod 7)开放定址散列 表。 h(4371)=1 a 分离链接散列表 { 4371, 1323, 6173, 4199, 4344, 9679, 1989 } 0 1 2 3 4 5 6 7 8 9 4371 ^ 6173 1323 ^ 4344 ^ 1989 9679 4199 ^ b使用线性探测的开放定址散列表 4371 mod 10 = 1 1323 mod 10 = 3 6173 mod 10 = 3 { 4371, 1323, 6173, 4199, 4344, 9679, 1989 } 0 9679 1 4371 2 1989 3 1323 4 6173 5 4344 6 7 8 9 4199 collision (3+1) mod 10 = 4 4199 mod 10 = 9 4344 mod 10 = 4 9679 mod 10 = 9 1989 mod 10 = 9 collision (9+2) mod 10 = 1collision (9+3) mod 10 = 2 c 使用平方探测的开放定址散列表 4371 mod 10 = 1 1323 mod 10 = 3 6173 mod 10 = 3 { 4371, 1323, 6173, 4199, 4344, 9679, 1989 } 0 9679 1 4371 2 3 1323 4 6173 5 4344 6 7 8 1989 9 4199 collision (3+12) mod 10 = 4 4199 mod 10 = 9 4344 mod 10 = 4 9679 mod 10 = 9 1989 mod 10 = 9 collision (9+22) mod 10 = 3collision (9+32) mod 10 = 8 d第二个散列函数为h2(x)=7-(x mod 7)开放定址散列表。 4371 mod 10 = 1 1323 mod 10 = 3 6173 mod 10 = 3 { 4371, 1323, 6173, 4199, 4344, 9679, 1989 } 0 1 4371 2 3 1323 4 6173 5 9679 6 7 4344 8 9 4199 collision (3+ h2(6173)) mod 10 = 4 4199 mod 10 = 9 4344 mod 10 = 4 9679 mod 10 = 9 collision (9+ 2*h2(9679)) mod 10 = 3collision (9+ 3*h2(9679)) mod 10 = 5 1989 mod 10 = 9 collision (9+ 2*h2(1989)) mod 10 = 1... 由于1989不能放入表中,进行再散列 新的hash函数为 h(x) = x mod 23 4371 mod 23 = 1 4199 mod 23 = 13 4344 mod 23 = 20 9679 mod 23 = 19 1989 mod 23 = 11 0 12 1323 1 4371 13 4199 2 14 3 15 4 16 5 17 6 18 7 19 9679 8 20 4344 9 6173 21 10 22 11 1989 2. 设散列表为HT[13],散列函数为 对下列关键码序列 12,23,45,57,20,03,78,31,15,36 :1) 画出其散列表。2)计算等概率下搜索成功的平均搜索长度。3)如果采用链表散列解决冲突,画出该链表。 0 78 1 1 2 15 1 3 3 1 4 5 57 1 6 45 1 7 20 1 8 31 4 9 10 23 1 11 36 2 12 12 1 平均搜索长度 =(1+1+1+1+1+1+4+1+2+1)/10=1.4 78 ^ 0 1 2 3 4 5 6 7 8 9 10 11 12 15 ^ 3 ^ 31 45 ^ 20 ^ 57 ^ 36 23 ^ 12 ^ 谢谢! QA
for (i=0;i
for ( j = i+1; j < n; j++)
} ?−1?−1 ?27
for( i = 0; i < n; i++ )
for( k = 0; k < j; k++ )
?=1 2 =?(?)
2) x = 0; y = 0;
1 = ?3
?=1 ?=1 ?=1
b.next = a.next.next
2. b.right = a.right.right;3. a.right.right = b;
to compute L1∩L2 using only the basic list operations.
新建链表L,存放L1∩L2的结果,故返回值类型为链表。 遍历L1和L2,比较L1、L2当前节点的值
LinkedListItr itr2 = L2.first();
LinkedList L = new LinkedList(); LinkedListItr itr = L.zeroth(); //返回header
to compute L1∪L2 using only the basic list operations.
LinkedListItr itr2 = L2.first();
LinkedList L = new LinkedList(); LinkedListItr itr = L.zeroth(); //返回header
else if(itr1.retrive() < itr2.retrive()) ()){
for(; !itr.isPastEnd(); itr.advance())
内循环只能执行一次从头到尾的循环
将node.next设为前一个node
将header.next指向最后一个元素
ListNode p1 = header.next;
ListNode p2 = p1.next;
if (p2 == null) return;
ListNode p3 = p2.next;
p1.next = null; //将firstNode.next设为null
p2 = p3;
p3 = p3.next;
p2.next = p1; //最后一个元素指向倒数第二个元素header.next = p2; //将头指针指向最后一个元素
p1.next = null放在while循环后 p2.next = p1 遗漏
最后忘了赋值header.next
用2个指针反转链表
1. 如果P是最后一个节点, 就将tail指向P所在位置 ,再将原 来的tail回收.
head tail求队列中第一个元素的实际位置。
rear = (rear+1)%m; Q[rear] = x;
return Q[(rear-length+1+m)%m];
张源 [email protected]
(2)根据设计思想,采用C或C++或JAVA语言表述算法,关键之处给出注释。
Reverse(R,p,n-1);
Reverse(R,0,n-1);
将森林转换为对应的二叉树, 若在二叉树中, 结点u是结点v的父
20 + 10 +1 +10 + n = 20*4 + 10*3 + 1*2 + 10*1 + 1 n=82
B:树中一定没有度为1的结点
C:树中两个权值最小的结点一定是兄弟结点
方法二:根据计算的顺序写出二叉树
做题时使用
&&
?0 + ?1 + ?2 + ?3 + ... + ?? = ?1 + 2?2 + 3?3 + ... + ??? + 1
2)二叉树的中序序列与后序序列相同
if (root.left == null && root.right == null)
return leafNum(root.left) + leafNum(root.right);
BinaryNode tmp = root.left; root.left = root.right; root.right = tmp; switchLR(root.left); switchLR(root.right);
case '~':
default:
}
}
return (BinaryNode) stack.pop();}
带权外路径长度:2 * 5 + 3 * 5 + 6 * 4 + 9 * 3 + 14 * 3 + 15 * 3 + 16 * 2 + 17 * 2 = 229
5 6 7 10 11 25 36
7 10 11 11
6. 下列二叉排序树中, 满足平衡二叉树定义的是 B
7. 下列叙述中, 不符合m阶B 树定义要求的是 D
B. 所有叶结点都在同一层上
C. 各结点内关键字均升序或降序排列D. 叶结点之间通过指针链接
4
6
6
P has exactly one nonempty subtree P has exactly two nonempty subtrees
If k if(k<=0 || t==null)
return null;
if(k
else if(k>t.leftsize)
return findkth(t.right ,k-
t.leftsize);
return t;
9 16
9 28
7 18
7 18
7 18
15
7 18
或者是空树
如果不是空树,则对于任意一个节点
If (n==null) return true;
If (n.left!=null && max(n.left).element>n.element)
If (n.right!=null && min(n.right).element
return isBST(n.left) && isBST(n.right);
If (n==null) return null;
While (n.right!=null) { n=n.right; } Return n;
If (n==null) return null;
While (n.left!=null) { n=n.left; } Return n;
List l = inOrderList(n);
int i,j; For(i=0,j=1;j
Return l;
11
15
FEB OCT
FEB OCT
FEB OCT 右单旋转
MAR
JUL MAY
AUG
OCT
OCT
APR JUN
AUG
60 80
80
20 40 70
95 20 40
60 80
80
2535 50 6070 85 95
60 65 70 85 95
50 60 70 85 9
2535 50 60 70 85 95 2535
55 80
15 35 50 60 70 85 95
85 95
55 80
15 35 50 60 70 85 95
85 95
55 80
15 3540 50 60
85 95
85 95
15 30 35 40 50 60 70 85 95
85 95
N 0 + 1 =2 , N 1 + 1 = 3 , N2 + 1 = 5 , N 3 + 1 = 8 , N4 + 1 = 13 , . . .
|——— | < 1 , ∴ —— ( ——— ) 相当小
N h + 1 = —— ( ——— ) + O ( 1 )∵费波那契数树是具有相同高度的所有平衡二叉树中结点
个数最少的
∵费波那契数树是具有相同高度的所有平衡二叉树中结点
n +1≥Nh +1= —— ( ——— )
∴ h≤———— log (n+1)+0(1)≈—log (n+1)
2 -1=n,所以h=log 2 (n+1)-1.
h(1323)=h(6173)=3
h(4344)=4
h(4199)= h(1989)= h(9679)= 9
collision (4+1) mod 10 = 5
collision (9+1) mod 10 = 0
collision (9+1) mod 10 = 0
collision (4+12) mod 10 = 5
collision (9+1) mod 10 = 0
collision (9+12) mod 10 = 0
collision (4+ h2(4344)) mod 10 = 7
collision (9+ h2(9679)) mod 10 = 1
collision (9+ h2(1989)) mod 10 = 5
collision (9+ 5*h2(1989)) mod 10 = 9
新的表长为原表大小两倍后的第一个质数,该问题中为23。
1323 mod 23 = 12
6173 mod 23 = 9
H(key) = key % 13 。用线性开地址法解决冲突,