数据结构学习笔记8 树 课后习题

本文详细探讨了关于AVL树的习题,包括如何找到高度为H的最小AVL树以及如何生成理想二叉查找树。通过对4.29、4.30和4.31题的解析,深入理解AVL树的特性和构建方法。
摘要由CSDN通过智能技术生成

4.29参考了答案

#include <STDIO.H>
#include <stdlib.h>

typedef struct Node * RanTree;
typedef RanTree Position;
struct Node
{
	 int Data;
	 RanTree Left;
	 RanTree Right;
};

RanTree SearchTree(int N);
RanTree RandomSearchTree(int Low,int Upper);
int RandomNum(int Low,int Upper);
void ListDir(RanTree T,int Depth,int Flag);
void PrintName(RanTree T,int Depth,int Flag);


RanTree SearchTree(int N)
{
	 RanTree H;
	 H=RandomSearchTree(1,N);
	 return H;
}
RanTree RandomSearchTree(int Low,int Upper)
{
	 Position P;

	 P=NULL;//这里对P赋值是为了对树叶的左右子树赋值为NULL
	 if (Low<=Upper)
	 {
		  P=(Position)malloc(sizeof(struct Node));
		  P->Data=RandomNum(Low,Upper);
		  P->Left=RandomSearchTree(Low,P->Data-1);
		  P->Right=RandomSearchTree(P->Data+1,Upper);
	 }
	 return P;
}
int RandomNum(int Low,int Upper)
{
	 return (rand() % (Upper-Low+1))+ Low;//产生Low和Upper之间的随机数
}
void ListDir(RanTree T,int Depth,int Flag)
{
	 if (T!=NULL)
	 {
		  
		  PrintName(T,Depth,Flag);
		  
		  RanTree T1,T2;
		  T1=T->Left;
		  ListDir(T1,++Depth,1);//这里处理深度问题
		  T2=T->Right;
		  ListDir(T2,Depth,2);
	 }	 
}
void PrintName(RanTree T,int Depth,int Flag)
{
	 int i;
	 for (i=0;i<Depth;i++)
		  printf("	");
	 if(Flag==1) 
		  printf("Left:");
	 else if(Flag==2) 
		  printf("Right:");
	 else printf("ROOT:");
	 printf("%d\n",T->Data);
	 
}
int main(void)
{
	 int N=15;

	 RanTree H;
	 H=SearchTree(N);
	 ListDir(H,0,0);

	 return 0;
}
运行时间为O(N)

4.30求高度为H的最小的AVL树

妈蛋啊,要哭了。竟然花了将近4个小时,1.5h用于构建AVL树,2.5h用于赋值
这个图可以有助于理解最小的AVL树。
#include <stdio.h>
#include <STDLIB.H>
#include "H_height_minimum_AVL.h"

#define  H 5

struct AvlNode
{
	 int Data;
	 AvlTree Left;
	 AvlTree Right;
	 int TreeHeight;
};
void ListDirectory(AvlTree T)//先序遍历打印树
{
	 ListDir(T,0,0);
}
void ListDir(AvlTree T,int Height,int Flag)
{
	 if (T!=NULL)
	 {
		  
		  PrintName(T,Height,Flag);
		  
		  Position T1,T2;
		  T1=T->Left;
		  ListDir(T1,++Height,1);//这里处理深度问题
		  T2=T->Right;
		  ListDir(T2,Height,2);
	 }	 
}
void PrintName(AvlTree T,int Height,int Flag)
{
	 int i;
	 for (i=0;i<Height;i++)
		  printf("	");
	 if(Flag==1) 
		  printf("Left:");
	 else if(Flag==2) 
		  printf("Right:");
	 else printf("ROOT:");
	 printf("%d  DATA=%d\n",T->TreeHeight,T->Data);
	 
}
AvlTree HminimunAVL(int Height,AvlTree P)//计算树各个节点的高度
{
	 if(Height>=0)
	 {
		  Position tmpCell;
		  tmpCell=(Position)malloc(sizeof(struct AvlNode));
		  tmpCell->TreeHeight=Height;
		  
		  tmpCell->Right=NULL;
		  tmpCell->Left=NULL;
		  if(Height)
		  {
			   tmpCell->Right=HminimunAVL(Height-1,P);//递归调用
			   tmpCell->Left=HminimunAVL(Height-2,P);
			   if (Height==1)
			   {
					tmpCell->Left=NULL;//对于左子树的创建时Height-2。当Height=1时在HminimumAVL函数中不符合判断条件,就没有对左子树赋值NULL。这里加入
					
			   }		  
			   /*tmpCell->Left->Right=NULL;
			   tmpCell->Left->Left=NULL;
			   tmpCell->Right->Right=NULL;	
			   tmpCell->Right->Left=NULL;*/
		  }	
		  P=tmpCell;
		  //free(tmpCell);这里不能free,不然新创建的节点就不存在了
		  return P;
	 }	 
}

AvlTree InsertData(AvlTree Tree,int i)//
{
	 
	 if(Tree->Left!=NULL)
	 {
		  Tree->Left=InsertData(Tree->Left,i);//这里的赋值应该是针对Tree->Left
		  i=MaxTree(Tree);//这里处理数据,为了不利用全局变量。每次调用函数之后进行数据插入之后,应当把当前树的最大值返回给father,便于后面的father节点赋值&右兄弟赋值
	 }
	 /*else 这里不需要else。最小的AVL树在当前节点可能不存在左子树,但是当前节点一定需要赋值Data
	 {*/
		  		  
		  Tree->Data=++i;
		  if (Tree->Right!=NULL)//判断右子树的情况,进行赋值
		  {
			   Tree->Right=InsertData(Tree->Right,i);
			   i=MaxTree(Tree);
		  }
	 /*}*/
	 

	 return Tree;
}
int MaxTree(AvlTree Tree)
{
	 int i,j,k;

	 i=Tree->Data;
	 if (Tree->Right)
	 {
		  j=MaxTree(Tree->Right);
	 }
	 if (Tree->Left)
	 {
		  k=MaxTree(Tree->Left);
	 }
	 i=i>j?i:j;
	 i=i>k?i:k;
	 return i;
}

int main(void)
{
	 AvlTree H_min_AVL;
	 //H_min_AVL=(Position)malloc(sizeof(struct AvlNode));
	 H_min_AVL=HminimunAVL(H,H_min_AVL);
	 H_min_AVL=InsertData(H_min_AVL,0);
	 ListDirectory(H_min_AVL);
	 return 0;
}
以上程序中,我在编写时候,怎么处理 i 这个数据花了很长时间。当时不想用全局变量,选择了当前树的最大值。其实,还有一个很简便的方法:用指针NodeData指向 i ,每次调用 i 都是*NodeData代替。这样就不存在不同层次递归调用 i 的当前值不同的问题。

4.31生成高度为H具有关键字2^(H+1)-1的理想二叉查找树

毫无疑问,这个理想的二叉查找树除叶子以外的所有节点都应该是Full Node,即每个节点有两个儿子。而且我们可以设定是编程之前已知树的形状,只需建立这个树并顺序插入数据即可。即,这个题目主要做的是4.30中为每个节点赋值的工作。
AvlTree H_AVL(int HEIGHT,int *i_pointer)//计算树各个节点的高度
{
	 Position tmpCell;
	 tmpCell=NULL;

	 if(HEIGHT>=0)
	 {
		  tmpCell=(Position)malloc(sizeof(struct AvlNode));
		  tmpCell->Left=H_AVL(HEIGHT-1,i_pointer);
		  tmpCell->TreeHeight=HEIGHT;
		  tmpCell->Data=++*i_pointer;
		  tmpCell->Right=H_AVL(HEIGHT-1,i_pointer);//递归调用
		  		  		  
	 }	 
	 return tmpCell;
}
int main(void)
{
	 AvlTree H_Tree;
	 int i=0;

	 
	 
	 H_Tree=H_AVL(5,&i);

	 ListDirectory(H_Tree);
	 return 0;
}


PS:基本上之前看的书,都做了课后习题。有些是自己写,有些参考了课后答案。但是进度太慢。之后不会再做课后习题,只会实现书上demo。然后多看书,在项目中应用所学。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值