数据结构整理

 

 

习题讲解

张源 [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

 



2nn

2

n1n1

 

1i0ji

 

错误的方法

 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;
for (i=0;i

mini = i;
for ( j = i+1; j < n; j++)

if ( a[j] < a[mini]) mini = j;

tmp = a[i];

a[i] = a[mini];

a[mini] = tmp;
} ?−1?−1 ?27

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( i = 0; i < n; i++ )

for( j = 0; j

sum++; sum = 0;

for( i = 1; i < n; i++ ) for( j = 0; j < i*i; j++ )

if( j % i == 0 )
for( k = 0; k < j; k++ )

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 2 =?(?)

?−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];

}
2) x = 0; y = 0;

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 = ?3

?=1 ?=1 ?=1

 

?
?=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
b.next = a.next.next

 

双链表

 

1

2

 

3

 

6

 

4a5bcd

 

1. a.right = b.right;
2. b.right = a.right.right;3. a.right.right = b;

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
to compute L1∩L2 using only the basic list operations.

3.2 给定两个已排序的表L1和L2,只使用基本的链表操作编 写计算L1∩L2的过程。

 

分析

 假设链表节点已按照节点值从小到大排列。
 新建链表L,存放L1∩L2的结果,故返回值类型为链表。 遍历L1和L2,比较L1、L2当前节点的值

 L1当前节点值=L2当前节点值,把该节点加入L,同 时L1、L2前进

 L1当前节点值L2当前节点值,L2前进 若L1或者L2为空,停止遍历

 返回L。

 

代码

public LinkedList intersection (LinkedList L1,LinkedList L2){

 

LinkedListItr itr1 = L1.first();
LinkedListItr itr2 = L2.first();
LinkedList L = new LinkedList(); LinkedListItr itr = L.zeroth(); //返回header

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
to compute L1∪L2 using only the basic list operations.

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();
LinkedListItr itr2 = L2.first();
LinkedList L = new LinkedList(); LinkedListItr itr = L.zeroth(); //返回header

 

 

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()) ()){

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循环嵌套
 for(; !itr.isPastEnd(); itr.advance())
 内循环只能执行一次从头到尾的循环

 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

 对于其他节点
 将node.next设为前一个node

 最后对于头指针
 将header.next指向最后一个元素

 

 

代码

public void reverse() {
ListNode p1 = header.next;

if (p1 == null) return;
ListNode p2 = p1.next;
if (p2 == null) return;
ListNode p3 = p2.next;
p1.next = null; //将firstNode.next设为null

// node.next设为前一个node ,然后指针前移一个位置

while (p3 != null) { p2.next = p1;

p1 = p2;
p2 = p3;
p3 = p3.next;

}
p2.next = p1; //最后一个元素指向倒数第二个元素header.next = p2; //将头指针指向最后一个元素

}

 

注意

 未判断p1和p2为空情况
 p1.next = null放在while循环后 p2.next = p1 遗漏
 最后忘了赋值header.next
 用2个指针反转链表

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替

换*/ }

}

 

 

删除算法:
1. 如果P是最后一个节点, 就将tail指向P所在位置 ,再将原 来的tail回收.

2. 否则,用P下一节点中元素的值替换P节点中的值,再删除P的下一节点

 

P
head tail

 

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++;
rear = (rear+1)%m; Q[rear] = x;

public Object dequeue() throws Underflow{ /*出队*/ if(isEmpty()){

throws new Underflow();

} else{

} }

length--;
return Q[(rear-length+1+m)%m];

 

关于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
张源 [email protected]

张仁涛 [email protected]

 

Chapter3.1 2010年全国考研统考题

 设将n(n,1)个整数存放到一维数组R中,试设 计一个在时间和空间两方面尽可能有效的算法, 将R中保有的序列循环左移P(0

 (1)给出算法的基本设计思想。
 (2)根据设计思想,采用C或C++或JAVA语言

表述算法,关键之处给出注释。

 

 (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);
 Reverse(R,p,n-1);
 Reverse(R,0,n-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的父

结点的父结点, 则在原来的森林中, 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
20 + 10 +1 +10 + n = 20*4 + 10*3 + 1*2 + 10*1 + 1 n=82

 

6

 对n(n大于等于2)个权值均不相同的字符构 成哈夫曼树,关于该树的叙述中,错误的 是()

 A:该树一定是一棵完全二叉树
 B:树中一定没有度为1的结点
 C:树中两个权值最小的结点一定是兄弟结点

 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))||az)

&&的优先级比||高

 

||
&&

 

> +-<

||

 

>xyyz

 

abcdaf

<

 

2. 如果一棵树有n1个度为1的结点,有n2个 度为2的结点,......,nm个度为m的结点,

试问有多少个度为0的结点?写出推导过程。

节点数 = 边数 + 1
?0 + ?1 + ?2 + ?3 + ... + ?? = ?1 + 2?2 + 3?3 + ... + ??? + 1

?0=?2+2?3+3?4+...+ ?−1??+1

 

3.分别找出满足以下条件的所有二 叉树

 1)二叉树的前序序列与中序序列相同NLR===LNR

So:所有节点都没有左节点、只有根节点、空树
 2)二叉树的中序序列与后序序列相同

LNR===LRN So:所有节点都没有右节点、只有根节点、空树

 3)二叉树的前序序列与后序序列相同NLR===LRN

 

So:只有根节点、空树

 

4.若用二叉链表作为二叉树的存储 表示,试对以下问题编写递归算法。

 1)统计二叉树中叶结点的个数。

public static int leafNum(BinaryNode root) {if (root == null)

return 0;
if (root.left == null && root.right == null)

return 1;
return leafNum(root.left) + leafNum(root.right);

}

 

 2)以二叉树为参数,交换每个结点的左子女和右 子女

public static void switchLR(BinaryNode root) {if (root == null)

return;
BinaryNode tmp = root.left; root.left = root.right; root.right = tmp; switchLR(root.left); switchLR(root.right);

}

 

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 '^':





 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;



 default:


}
}
 return (BinaryNode) stack.pop();}

 

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
带权外路径长度:2 * 5 + 3 * 5 + 6 * 4 + 9 * 3 + 14 * 3 + 15 * 3 + 16 * 2 + 17 * 2 = 229

 

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 7 10 11 25 36

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
7 10 11 11

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]

 

统考题:
6. 下列二叉排序树中, 满足平衡二叉树定义的是 B

A. B. C.

 

D.

 

统考题:
7. 下列叙述中, 不符合m阶B 树定义要求的是 D

A. 根结点最多有m棵子树
B. 所有叶结点都在同一层上
C. 各结点内关键字均升序或降序排列D. 叶结点之间通过指针链接

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
4

33

 

3

 

1

14
6

14
6

9

 

333 141414

 

26262695959

7

 

 P is a leaf
 P has exactly one nonempty subtree P has exactly two nonempty subtrees

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本身
 If k  If k>n.leftsize,则目标元素在右子树中

Public BinaryNode findkth(BinaryNode t,int k) {

      if(k<=0 || t==null)
            return null;
      if(k
      else if(k>t.leftsize)
            return findkth(t.right ,k-
            t.leftsize);

else
return t;

}

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
9 16

 

 

7 3

9

28 11

7 39

1111 左单 7

 

16

3

16
9 28

11
7 18

28

 

16

28 18

右双

 

3 9 16

 

 

11
7 18

3 9 16 14

11
7 18

28

14
15

 

28

3 9 16

 

左双

 

11
7 18

 

3 9 15

28 14 16

 

Exercise 4

 写一个程序判断一个二叉树是不是二叉搜索树 二叉搜索树必须满足:
 或者是空树
 如果不是空树,则对于任意一个节点

左子树(如果有)中所有节点都小于该节点 右子树(如果有)中所有节点都大于该节点

左子树(如果有)也是二叉搜索树右子树(如果有)也是二叉搜索树

方法1:检验左子树的最大值和右子树的最小 值

 Public boolean isBST(Node n) {
If (n==null) return true;
If (n.left!=null && max(n.left).element>n.element)

return false;
If (n.right!=null && min(n.right).element

return false;
return isBST(n.left) && isBST(n.right);

}

方法1

 Public Node max (Node n) {
If (n==null) return null;
While (n.right!=null) { n=n.right; } Return n;

}

 Public Node min (Node n) {
If (n==null) return null;
While (n.left!=null) { n=n.left; } Return n;

}

方法2:中序排列

 Public boolean isBST(Node n) {If(n==null) return true;
List l = inOrderList(n);
int i,j; For(i=0,j=1;j

if(l.get(i)>=l.get(j)) return false; }

Return true;}

方法2

 Public List inOrderList(Node n) {List l = new ArrayList(); inOrderList(n, l);
Return 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
11

12
15

 

 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
FEB OCT

SEP

NOV
FEB OCT

 

NOV JUL OCT

左单旋转

 

DEC

JUL

 

SEP

 

DEC AUG

JUL

SEP

 

APR, MAR, MAY, JUN, JAN

 

NOV
FEB OCT 右单旋转

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
MAR

AUG DEC

MAR
JUL MAY

 

JUN, JAN

NOV FEB

OCT

左双旋转

MAR FEB

 

AUG DEC

MAR

SEP
AUG

NOV
OCT

SEP

 

APR

JUL MAY

APR JUN

JUL MAY JUN

 

DEC

 

JAN

 

MAR FEB

NOV
OCT

 

APR

AUG DEC

JUL MAY

JUN

SEP

 

JAN

按月份的结果

JUL MAR

OCT

NOV DEC

 

FEB
APR JUN

 

MAY
AUG

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
60 80

55
80

 

30
20 40 70

30
95 20 40

60 70

95

 

 Delete 4050

60 80 20 5570

 

30

 

95

 

20 30

50
60 80

55 70

95

50 20 30

60
80

70 95

55

 10. 分别画出插入65, 15, 40, 30后的3阶B-树。55

 

45
2535 50 6070 85 95

80 90

 

 

55

 

 插入65

45

80 90
60 65 70 85 95

 

55

55 80

65
50 60 70 85 9

25 35

50

 

45
2535 50 60 70 85 95 2535

6580 90

45

90

 

5

 插入15
55 80

45

 

65 90 25355060708595 5580

 

25 45
15 35 50 60 70 85 95

90
85 95

65 90

 

55 80 45

65

 

15 25 35

50 60

70

 插入40
55 80

25 45
15 35 50 60 70 85 95

 

65 90

 

55 80 25 45

15 3540 50 60

65

90
85 95

 

70

 插入30
55 80

25 45
15 3540 50 60

65

90
85 95

55 80 25 35 45

 

70

 

65

90
85 95

 

55 80 25 45

15 30 40

50 60

70

 

65
15 30 35 40 50 60 70 85 95

90

 

 

35 55 80 25 45

65 90

 

15 30 40

50 60

70

85

95

 

55

 

35 25 45

80

 

65

90
85 95

 

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 , . . .
N 0 + 1 =2 , N 1 + 1 = 3 , N2 + 1 = 5 , N 3 + 1 = 8 , N4 + 1 = 13 , . . .

 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 , ∴ —— ( ——— ) 相当小

 

1+√52

 

h +3
N h + 1 = —— ( ——— ) + O ( 1 )

1√5

i

 

∵费波那契数树是具有相同高度的所有平衡二叉树中结点
   个数最少的

2

1+√5

h +3

 

1n+1≥Nh+1=——(———) +O(1)

√5

 

对于一个有N 个结点的AVL 树, 其最大高 度是多少? 最小高度是多少?

 ∵费波那契数树是具有相同高度的所有平衡二叉树中结点

个数最少的,
n +1≥Nh +1= —— ( ——— )

1 1+√5 √5 2

h +3

+ O( 1 )

1
∴ h≤———— log (n+1)+0(1)≈—log (n+1)

i

 

3

 

1+√5 2 2log ——

2

2

2

这就是h的最大值; 至于h的最小值,是一颗完全二叉树的时候,高度最小,有

h +1
2 -1=n,所以h=log 2 (n+1)-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
 h(1323)=h(6173)=3
 h(4344)=4
 h(4199)= h(1989)= h(9679)= 9

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
collision (4+1) mod 10 = 5

9679 mod 10 = 9
collision (9+1) mod 10 = 0

1989 mod 10 = 9
collision (9+1) mod 10 = 0

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
collision (4+12) mod 10 = 5

9679 mod 10 = 9
collision (9+1) mod 10 = 0

1989 mod 10 = 9
collision (9+12) mod 10 = 0

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
collision (4+ h2(4344)) mod 10 = 7

9679 mod 10 = 9
collision (9+ h2(9679)) mod 10 = 1

collision (9+ 2*h2(9679)) mod 10 = 3collision (9+ 3*h2(9679)) mod 10 = 5

1989 mod 10 = 9
collision (9+ h2(1989)) mod 10 = 5

collision (9+ 2*h2(1989)) mod 10 = 1...
collision (9+ 5*h2(1989)) mod 10 = 9

 由于1989不能放入表中,进行再散列
 新的表长为原表大小两倍后的第一个质数,该问题中为23。

新的hash函数为 h(x) = x mod 23 4371 mod 23 = 1
1323 mod 23 = 12
6173 mod 23 = 9

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],散列函数为
H(key) = key % 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

你可能感兴趣的:(数据结构整理)