21考研复习之《数据结构》——《树与二叉树》王道课本149页代码题目

3、编写后续遍历二叉树的非递归算法

LeetCode

void PostOrder(BiTree T){
	InitStack(S);
	p = T;
	r = NULL;
	while(p||!IsEmpty(S)){
		if(p){ //走到最左边
			push(S, p);
			p = p->lchild;
		}
		else{
			GetTop(S, p);       //读栈顶结点(非出栈)
			if(p->rchild&&p->rchild!=r){ // 若右子树存在,且未被访问过
				p = p->rchild;
				push(S, p); //右子树入栈
				p = p->lchild;
			}
			else{	//否则,弹出结点并访问
				pop(S, p);
				visit(p->data);
				r = p;       //r指针标记当前结点已经访问过了
				p = NULL;
			}
		}
	}
}

4、试给出二叉树的自下而上、从右到左的层次遍历算法。

层次遍历入栈,再弹栈即可

void InvertLevel(BiTree bt){
	Stack s;
	Queue Q;
	if(bt!=NULL){
		InitStack(s);
		InitQueue(Q);
		EnQueue(Q, bt);
		while(IsEmpty(Q)==false){ //队列不空
			Dequeue(Q, p);
			Push(s, p); //出队入栈
			if(p->lchild)
				EnQueue(Q, p->lchild);
			if(p->rchild)
				EnQueue(Q, p->rchild);	
		}
		while(IsEmpty(s)==false){ //访问栈
			Pop(s, p);
			visit(p->data);
		}
	}
}

5、假设二叉树采用二叉链表存储结构,设计一个非递归算法求二叉树的高度。

采用层次遍历,设置变量level记录当前结点所在的层数,设置变量last指向当前层的最有结点,每次层次遍历出队时与last指针比较,若两者相等,则层数加1,并让last指向下一层的最右结点,直到遍历完成。level的值即为二叉树的高度。

int BtDepth(BiTree T){
//采用层次遍历的非递归方法求解二叉树的高度
	if(!T)
		return 0;        //树空,高度为0
	int front=-1, rear=-1;
	int last=0,level=0;
	BitTree Q[MaxSize];
	Q[++rear] = T;         //将根节点入队
	BitTree p;
	while(front<rear){   //队不空,则循环
		p = Q[++front];  //对头元素出队
		if(p->lchild)
			Q[++rear] = p->lchild;
		if(p->rchild)
			Q[++rear] = p->rchild;
		if(front==last){ //处理该层的最右结点
			level++;
			last = rear;  // last指向下一层
		}		
	}
	return level;	
}

版本2
最大深度

    int maxDepth(TreeNode* root) {
        if(root==NULL)
            return 0;
        vector<TreeNode*> q; //使用线性表模拟队列
        TreeNode *p;
        int i=0,j=1, level=0;
        q.push_back(root); 
        while(i<j){
            for(int k=i;k<j;k++){
                p = q[k];
                if(p->left)
                    q.push_back(p->left);
                if(p->right)
                    q.push_back(p->right);    
            }
            level++;
            i=j;
            j=q.size();
        }
        return level;
    }

6、设一棵二叉树中各结点的值互不相同,其先序遍历序列和中序遍历序列分别存在于两个一维数组A[1…n]和B[1…n]中,试编写算法建立该二叉树的二叉链表。

BiTree PreInCreat(ElemType A[], ElemType B[], int l1,int h1,int l2,int h2){
//l1,h1为先序的第一个和最后一个结点下标,l2,h2为中序的第一个和最后一个结点下标
//初始调用时,l1=l2=1, h1=h2=n
	root = (BiTNode*)malloc(sizeof(BiTNode));     //建根节点
	root->data=A[l1];
	for(int i=l2;B[i]!=root->data;i++);          // 根节点在中序序列中的划分
	llen=i-l2;
	rlen=h2-i;
	if(llen)
		root->lchild=PreInCreat(A, B, l1+1, l1+len, l2, l2+llen-1);
	else
		root->lchild=NULL;
	if(rlen)
		root->rchild=PreInCreat(A, B, h1-rlen+1, h1, h2-rlen+1, h2);
	else
		root->rchild=NULL;
	return root;					
}

C++语言
LeetCode

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return reBuiltBTree(preorder, inorder, 0, preorder.size()-1, 0, inorder.size()-1);
    }
    TreeNode* reBuiltBTree(vector<int> A, vector<int> B, int l1, int r1, int l2, int r2){
        if(l1>r1)
            return NULL;
        TreeNode* curr = new TreeNode();
        curr->val = A[l1];
        int root;
        for(root=l2;B[root]!=A[l1];root++); //找到根节点在中序遍历中的位置
        int llen=root-l2; //左子树的长度
        int rlen=r2-root; //右子树的长度
        if(llen)//左子树
            curr->left = reBuiltBTree(A, B, l1+1, l1+llen, l2, root-1);
        else
            curr->left = NULL;
        if(rlen) //右子树
            curr->right = reBuiltBTree(A, B, l1+llen+1, r1, root+1, r2);   
        else
            curr->right = NULL;
        return curr;            
    }
};

7、二叉树按二叉链表形式存储,写一个判别给定二叉树是否是完全二叉树的算法。

bool IsComplete(BiTree T){
// 本算法判断给定二叉树是否为完全二叉树
	InitQueue(Q);
	if(!T)
		return 1; // 空二叉树为满二叉树
	EnQueue(Q, T);
	while(!IsEmpty(Q)){
		DeQueue(Q, p);
		if(p){ //结点非空,将其左子树、右子树加入队列
			EnQueue(Q, p->lchild);
			EnQueue(Q, p->rchild);	
		}
		else{ //结点为空,检查其后是否有非空结点
			while(!IsEmpty(Q)){
				DeQueue(Q, p);
				if(p)
					return 0;
			}
		}
	}
	return 1;	
}

8、假设二叉树采用二叉链表存储结构存储,试设计一个算法,计算一棵给定二叉树的所有双分支节点个数。

int DsonNodes(BiTree b){
	if(b==NULL)
		return 0;
	else if(b->lchild!=NULL&&b->rchild!=NULL)
		return DsonNodes(b->lchild) + DsonNodes(b->rchild) + 1;
	else
		return DsonNodes(b->lchild) + DsonNodes(b-rchild);		
}

9、设树B是一棵采用链式结构存储的二叉树,编写一个把树B中所有结点的左、右子树进行交换的函数。

void swap(BiTree b){
	if(b){
		swap(b->lchild);
		swap(b->rchild);
		temp = b->lchild;
		b->lchild = b->rchild;
		b->rchild = temp;
	}
}

10、假设二叉树采用二叉链存储结构存储,设计一个算法,求先序遍历序列中第k(1<=k<=二叉树中结点个数)个结点的值。

int i=1;
ElemType PreNode(BiTree b, int k){
//本算法查找二叉树先序遍历中第k个结点的值
	if(b==NULL)
		return '#';
	if(i==k)
		return b->data;
	i++;
	ch = PreNode(b->lchild, k); //在左子树递归查找
	if(ch!='#')
		return ch;
	ch = PreNode(b-rchild, k); // 在右子树递归查找
	if(ch!='#')
		return ch;			
}

11、已知二叉树以二叉链表存储,编写算法完成:对于树中每个元素值为x的结点,删去以它为根的子树,并释放相应的空间。

对于树的搜索,可以使用层次遍历,也可以是用前序遍历。

void DeleteXTree(BiTree bt){ //删除以bt为根的子树
	if(bt){
		DeleteXTree(bt->lchild);
		DeleteXTree(bt->rchild);
		free(bt);
	}
}
// 在二叉树中查找所有以x为元素值的结点,并删除以其为根的子树
void Search(BiTree bt, ElemType x){
	BiTree Q[];      //Q是存放二叉树结点指针的队列,容量足够大
	if(bt){
		if(bt->data==x){ //若根节点值为x,删除整棵树
			DeleteXTree(bt);
			exit(0);
		}
		InitQueue(Q);
		EnQueue(Q, bt);
		//采用层次遍历的方式,自上而下,非递归遍历每个结点
		while(!IsEmpty(Q)){
			DeQueue(Q, p);
			if(p->lchild){ //左子树非空
				if(p->lchild->data==x){
					DeleteXTree(p->lchild);
					p->lchild = NULL;
				}
				else
					EnQueue(Q, p->lchild);
			}
			if(p->rchild){
				if(p->rchild->data==x){
					DeleteXTree(p->rchild);
					p->rchild = NULL;
				}
				else
					EnQueue(Q, p->rchild);
			}
		}
	}
}

12、在二叉树中查找值为x的结点,试编写算法(用C语言)打印值为x的结点的所有祖先,假设值为x的结点不多于1个。

后序遍历,回溯到根节点中止,非王道课本,我觉得课本写的不太好,甚至有bug

int flag=0; //flag为1表示已经找到x
void Search(BiTree bt, ElemType x){
	if(bt){
		if(bt->data==x)
			flag=1; //标记x已经找到
		if(flag==0)	// x已经找到的情况下,没必要再继续往深处遍历 
			Search(bt->lchild, x);
		if(flag==0) //左子树没有搜到的情况下才会搜右子树		
			Search(bt->rchild, x);
		if(flag==1&&bt->data!=x)  //注意不要打印当前结点为x的结点
			printf("%d\n",bt->data); // 以该结点为根节点,找到了x,那么打印当前结点的值
	}	
}

13、设一棵二叉树的结点结构为(LLINK, INFO, RLINK),ROOT为指向该二叉树根节点的指针,p和q分别为指向该二叉树中任意两个结点的指针,试编写算法ANCESTOR(ROOT, p, q, r),找到p和q的最近公共祖先结点r。

递归算法

BiTree Ancestor(BiTree ROOT, BiTNode *p, BiTNode *q){
/*求最近公共祖先的递归算法*/
	if(ROOT==NULL||ROOT==q||ROOT==q)
		return ROOT;
	BiTNode *left = Ancestor(ROOT->lchild, p, q);
	BiTNode *right = Ancestor(ROOT->rchild, p, q);
	if(left==NULL) //左子树中不存在p或q
		return right;
	if(right==NULL) //右子树不存在p或者q
		return left;
	return ROOT; //左右子树分配p和q			
}

这个看不懂啊,感觉很乱

typedef struct{
	BiTree t;
	int tag; //tag=0 表示左子女已经被访问,tag=1表示右子女已经被访问
}stack;
stack s[], s1[];
BiTree Ancestor(BiTree ROOT, BiTNode *p, BiTNode *q){
// 本算法求二叉树中p和q指向结点的最近公共结点
	top = 0;
	bt = ROOT;
	while(bt!=ROOT||top>0){
		while(bt!=NULL&&bt!=p&&bt!=q){ //结点入栈
			s[++top].t = bt;
			s[top].tag = 0;
			bt=bt->lchild;
		}
		while(top!=0&&s[top].tag==1){
		// 假定p在q的左侧,遇到p时,栈中元素为p的祖先
			if(s[top].t==p){
				for(i=1;i<=top;i++)
					s1[i]=s[i];
				top1=top;	
			}
			if(s[top].t==q){
				for(i=top;i>0;i--){ //将栈中元素的树结点到s1中去匹配
					for(j=top1;j>0;j--){
						if(s1[j].t==s[i].t)
							return s[i].t;
					}
				}
			}
			top--;
		}
		if(top!=0){
			s[top].tag=1;
			bt=s[top].t->rchild;
		}
	}	
	return NULL;
}

14、假设二叉树采用二叉链表存储结构,设计一个算法,求非空二叉树b的宽度(即具有结点数最多的那一层的结点个数)。

王道课本给出的答案是层次遍历每个结点,遍历的过程中入队的时候标记该结点的层数,最后再遍历队列(未抹去信息)中的所有结点,统计每个层次的结点数量,输出最大值。
再次我就不总结王道课本的算法了,感觉是最笨的算法,代码也不简练。
自我感觉写的不是很好,起始可以依次遍历直接求最大值

int BTWidth(BiTree b){
	if(b==NULL) 
		return 0; 
	vector<BiTree> q;
	q.push_back(b);
	int i=0,j=1;
	int ans=0;
	BiTree p;
	while(i<j){
		//每次出队的是一个层次的
		for(int k=i;k<j;k++){
			p = q[k];
			if(p->lchild)
				q.push_back(p->lchild);
			if(p->rchild)
				q.push_back(p->rchild);	
		}
		if(j-i>ans) //i为该层次左端,j为该层次的有段,左闭右开
			ans = j-i;
		//更新i和j
		i=j;
		j=q.size();
	}
	return ans;	
}

15、设有一棵满二叉树(所有结点值均不同),已知其先序序列为pre,设计一个算法求其后续序列post。

满二叉树的特点是任意根节点,左子树和右子树的长度是相等的。
例如前序:1 2 3 4 5 6 7,根节点为1,左子树为2 3 4,右子树为5 6 7

void PreToPost(ElemType pre[], int l1, int h1, ElemType post[], int l2, int h2){
	int half;
	if(h1>=l1){
		post[h2] = pre[l1]
		half = (h1-l1)/2;
		PreToPost(pre, l1+1, l1+half, post, l2, l2+half-1);
		PreToPost(pre, l1+half+1, h1, post, l2+half, h2-1);
	}
}

16、设计一个算法将二叉树的叶节点按从左到右的顺序连成一个单链表,表头指针为head。二叉树按二叉链表方式存储,链接时用叶结点的右指针域来存放单链表指针。

LinkedList head, pre=NULL;
LinkedList InOrder(BiTree bt){
	if(bt){
		InOrder(bt->lchild);      //中序遍历左子树
		if(bt->lchild==NULL&&bt->rchild==NULL) //叶节点
			if(pre==NULL){
				head = bt;
				pre = bt;
			}
			else{
				pre->rchild=bt;
				pre=bt;
			}
		InOrder(bt->rchild);     //中序遍历右子树
		pre->rchild=NULL;	//我觉得这句加不加无所谓,因为叶子结点的右子树本身就指向NULL
	}
	return head;
}

17、试设计判断两棵二叉树是否相似的算法。所谓二叉树T1和T2相似,指的是T1和T2都是空的二叉树或都只有一个根结点;或T1的左子树和T2的左子树是相似的,且T1的右子树和T2的右子树是相似的。

题目的意思就是树的形态是一致的,不过根据题目的描述,直接编写递归代码即可,和王道课本略有不同。

int similar(BiTree T1, BiTree T2){
// 采用递归算法判断两棵二叉树是否相似
	int leftS, rightS;
	if(T1==NULL&&T2==NULL)          // T1和T2都是空的二叉树
		return 1;
	else if(T1->lchild==NULL && T1->rchild==NULL
		&& T2->lchild==NULL && T2->rchild==NULL)  // T1 T2都只有一个根节点
		return 1;		
	else{
		leftS = similar(T1->lchild, T2->lchild);
		rightS = similar(T1->rchild, T2->rchild);
		return leftS&&rightS;
	}	
}

18、写出在中序线索二叉树里查找指定结点的后序的前驱结点的算法。

算法思想:若后序序列中,若结点p有右子女,则右子女是其前驱,若无右子女而有左子女,则左子女是其前驱。若结点p左、右子女均无,设其中序左线索指向某祖先结点f,(p是f右子树中按中序遍历的第一个结点),若f有左子女,则其左子女是结点p在后序下的前驱;若f无左子女,则顺其前驱找双亲的双亲,一直找到双亲有左子女(这时左子女是p的前驱)。还有一种情况,若p是中序遍历的第一个结点,则结点p在中序和后续下均无前驱。

BiThrTree InPostPre(BiThrTree t, BiThrTree p){
//在中序线索二叉树t中,求指定结点p在后序下的前驱结点q
	BiThrTree q; 
	if(p->rtag==0)
		q = p->rchild;
	else if(p->ltag==0)
		q = p->lchild;
	else if(p->lchild==NULL) //该结点在中序线索二叉树中没有前驱
		q = NULL;		
	else{ //顺左线索向上找p的祖先,若存在,再找祖先的左子女
		while(p->ltag==1&&p->lchild!=NULL)
			p = p->lchild;
		if(p->ltag==0)
			q = p->lchild;  // p结点的祖先的左子女是其后序前驱
		else
			q = NULL;       // 仅有单支树(p是叶子),已到根节点,p无后序前驱
	}	
	return q;
}

19、2014统考真题,二叉树的带权路径长度WPL

(1)基于先序递归遍历的算法思想是用一个static变量记录wpl,把每个结点的深度作为递归函数的一个参数传递,算法步骤如下:

  • 若该节点是叶结点,则变量wpl加上该结点的深度与权值之积。
  • 若该节点是非叶节点,则左子树不为空树时,对左子树调用递归算法,右子树不为空,对右子树调用递归算法,深度参数均为本结点的深度参数加1。
  • 最后返回计算出的wpl即可。
    (2)基于层次遍历的算法思想是使用队列进行层次遍历,并记录当前的层数:
  • 当遍历到叶节点时,累计wpl。
  • 当遍历到非叶结点时,把该结点的子树加入队列。
  • 当某节点为该层的最后一个结点时,层数自增1。
  • 队列为空时遍历结束,返回wpl

二叉结点的数据类型定义如下。

typedef struct BiTNode{
	int weight;
	struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

前序遍历

int WPL(BiTree root){
	return wpl_PreOrder(root, 0);
}
int wpl_PreOrder(BiTree root, int deep){
	static int wpl=0;
	if(root->lchild==NULL&&root->rchild==NULL)
		wpl += deep*root->weight;
	if(root->lchild!=NULL)
		wpl_PreOrder(root->lchild, deep+1);
	if(root->rchild!=NULL)
		wpl_PreOrder(root->rchild, depp+1);
	return wpl;		
}

层次遍历,鉴于王道课本写的代码不太好,我不写了,我自己写一个吧。


int wpl_LevelOrder(BiTree root){
	queue<BiTree> q;
	queue<int> deep;     //同步结点队列记录路径长度
	int ans=0;
	if(root==NULL)
		return 0;
	q.push(root);
	deep.push(0);
	while(!q.empty()){
		BiTree curr = q.top();
		q.pop(); //队首元素出队
		int d = deep.top();
		deep.pop();
		if(curr->lchild==NULL && curr->rchild==NULL)
			ans += deep*curr->weight;
		if(curr->lchild){
			q.push(curr->lchild);
			deep.push(d+1);
		}
		if(curr->rchild){
			q.push(curr->rchild);
			deep.push(d+1);
		}		
	}
	return ans;	
}

20、2017统考真题,算术表达式

1)算法的基本设计思想。
表达式树的中序序列加上必要的括号即为等价的中缀表达式。可以基于二叉树的中序遍历策略得到所需的表达式。
表达式树中分支结点所对应的子表达式的计算次序,由该分支所处的位置决定。为得到正确的中缀表达式,需要在生成遍历序列的同时,在适当位置增加必要的括号。显然,表达式式的最外层(对应根节点)和操作数(对应叶节点)不需要添加括号。
2)算法实现。
将二叉树的中序遍历递归算法稍加改造即可得到本体的答案。除根节点和叶结点外,遍历其他结点时在遍历其左子树之前加上左括号,遍历完右子树后加上右括号。

void BtreeToE(BTree *root){
	BtreeToExp(root, 1);  //根的高度为1
}
void BtreeToExp(BTree *root, int deep){
	if(root==NULL)
		return;
	else if(root->left==NULL&&root->right==NULL)// 叶子结点
		printf("%s", root->data);
	else{
		if(deep>1)
			printf("(");
		BtreeToExp(root->left, deep+1);
		prinft("%s", root->data);
		BtreeTpExp(root->rchild, deep+1);
		if(deep>1)
			printf(")");	
	}	
}

树、森林

5、编程求以孩子兄弟表示法存储的森林的叶子结点数。

孩子兄弟表示法是一棵二叉树,森林的叶子结点,在二叉树中表示为左指针为空。

typedef struct node{
	ElemType data;
	struct node *fch, *nsib;
}*Tree;
int Leaves(Tree t){ //计算以孩子兄弟表示法存储的森林的叶子树
	if(t==NULL)
		return 0;
	if(t->fch==NULL)
		return 1 + Leaves(t->nsib);
	else
		return Leaves(t->fch) + Leaves(t->nsib);		
}

6、以孩子兄弟链表为存储结构,请设计递归算法求树的深度。

树的深度等有所有子树中深度最大的树的深度+1

int Height(CSTree bt){
// 递归求以孩子兄弟链表表示的树的深度
	int hc,hs;
	if(bt==NULL)
		return 0;
	else{
		hc = Height(bt->firstchild);
		hs = Height(bt->nextsibling);
		if(hc+1>hs)
			return hc+1;
		else
			return hs;	
	}		
}

7、已知一棵树的层次序列及每个结点的度,编写算法构造此树的孩子兄弟-链表。

层次序列和每个结点的度已知,可以还原整棵树,结点父子关系可以确定。

#define maxNodes 15
void createCSTree_Degree(CSTree &T, DataType e[], int degree[], int n){
// 根据树结点的层次序列e[]和各结点的度degree[]构造树的孩子-兄弟结点链表
// 参数n是树结点个数
	CSNode *pointer = new CSNode[maxNodes]; //判断pointer[i]为空的语句未写
	int i,j,d,k=0;
	for(i=0;i<n;i++){ //初始化
		pointer[i]->data = e[i];
		pointer[i]->lchild=pointer[i]->rsibling = NULL;
	}
	for(i=0;i<n;i++){
		d = degree[i];           // 结点i的度数
		if(d){
			k++;
			pointer[i]->lchild=pointer[k];      //结点i的第一个孩子
			for(j=2;j<=d;j++){                  //结点i的剩下的d-1个孩子
				k++; 
				pointer[k-1]->rsibing = pointer[k];
			}
		}
	}
	T = pointer[0];
	delete [] pointer;     //我觉得这里的释放内存空间不合适。
}

树与二叉树的应用

6、试编写一个算法,判断给定的二叉树是否是二叉排序树

中序遍历升序

KeyType predt=-32767;
int JudgeBST(BiTree bt){
	int b1,b2;
	if(bt==NULL)     // 空树
		return 1;
	else{
		b1 = JudgeBST(bt->lchild);
		if(b1==0||predt >= bt->data)
			return 0;
		predt = bt->data;
		b2 = JudgeBST(bt->rchild);
		return b2;          //返回右子树的结果	
	}	
}

7、设计一个算法,求出指定结点在给定二叉排序树中的层次。

递归算法:搜索的过程中标记层次,子结点的层次是父节点层次+1,初始化根节点层次为1
非递归算法,使用一个标记,每次层次增加,标记+1

/*算法假设给定的结点一定可以找到*/
int level(BiTree bt, BSTNode *p){
// 本算法计算给定结点*p在二叉排序树中的层次
	int n=0;
	BiTree t=bt;
	if(bt!=NULL){
		n++;
		while(t->data != p->data)
			if(p->data < t->data)
				t = t->lchild;
			else
				t = t->rchild;
			n++;		
	}
}

8、利用二叉树遍历的思想编写一个判断二叉树是否是平衡二叉树的算法。

void Jundge_AVL(BiTree bt, int &balance, int &h){
// 本算法判断一个给定的二叉树是否未平衡二叉树
	int bl=0, br=0, hl=0, hr=0;     // 左右子树的平衡标记和高度
	if(bt==NULL){
		h=0;
		balance = 1;
	}		
	else if(bt->lchild==NULL&&bt->rchild==NULL){
		h=1;
		balance = 1;
	}
	else{
		Jundge_AVL(bt->lchild, bl, hl);
		Jundge_AVL(bt->rchild, br, hr);
		h = (hl>hr?hl:hr)+1;     // 取深度较深的那个子树再加1
		if(abs(hl-hr)<2)
			balance = b1&&br;
		else
			balance = 0;	
	}
}

9、设计一个算法,求出给定二叉排序树中最小和最大的关键字。

最左结点和最有结点

KeyType MinKey(BSTNode *bt){
// 求出二叉排序树中最小关键字结点
	while(bt->lchild!=NULL)
		bt = bt->lchild;
	return bt->data;	
}
KeyType MaxKey(BSTNode *bt){
// 求出二叉排序树中最大关键字结点
	while(bt->rchild!=NULL)
		bt = bt->rchild;
	return bt->data;	
}

10、设计一个算法,从大到小输出二叉排序树中所有值不小于k的关键字。

LNR遍历,遍历到第一个小于k的结点终止

void OutPut(BSTNode *bt, KeyType k){
// 本算法从大到小输出二叉排序树中所有值不小于k的关键字
	if(bt==NULL)
		return;
	if(bt>rchild!=NULL)
		OutPut(bt->rchild, k);
	if(bt->data >= k)
		printf("%d\n", bt->data);  // 只输出大于等于k的结点的值
	/*可以优化的是,如果确定了当前结点的值小于k,那么它的左子树一定也小于k,此时不用再遍历左子树*/
	if(bt->lchild!=NULL)
		OutPut(bt->lchild, k);		
}

更改版本如下:
由于不访问小于k的左子树,效率提高。

void OutPut(BSTNode *bt, KeyType k){
	if(bt==NULL)       //当前结点为空,do nothing
		return;
	OutPut(bt->rchild, k);     //访问右子树
	if(bt->data >= k){  // 如果当前结点小于k,那么左子树不再需要遍历,一定不满足。
		printf("%d\n", bt->data);
		OutPut(bt->lchild, k); // 访问左子树
	}	
}

11、设给定权集w={5,7,2,3,6,8,9},试构造关于w的一棵哈夫曼树,并求其加权路径长度WPL。

哈夫曼树的代码实现其实也可以完成,一般的题目都是手算

12、编写一个递归算法,在一棵有n个结点的、随机建立起来的二叉排序树上查找第k(1<=k<=n)小的元素,并返回指向该结点的指针。要求算法的平均时间复杂度为O(log2n)。二叉排序树的每个结点中除data,lchild,rchild等数据成员外,增加一个count成员,保存以该结点为根的子树上的结点个数。

BSTNode* Search_Small(BSTNode *t, int k){
// 在以t为根的子树上寻找第k小的元素,返回其所在结点的指针。k从11开始计算
// 在树结点中增加一个count数据成员,存储以该结点为根的子树的结点个数
	if(k<1 || k > t->count) //k的值不合法
		return NULL;
	if(t->lchild==NULL){
		if(k==1)
			return t;
		else
			return Search_Small(t->rchild, k-1);	
	}	
	else{
		if(t->lchild->count == k-1)  //左子树刚好有k-1个结点
			return t;              
		else if(t->lchild->count > k-1)
			return Search_Small(t->lchild, k); //去左子树搜索
		else{  // 左子树的结点不足k-1,去右子树再找一些
			return Search_Small(t->rchild, k - 1 - t->lchild->count)
		}		
	}
} 

你可能感兴趣的:(考研复习)