二叉搜索树的黑框树状显示(标准C语言实现)
最近在用C语言实现平衡二叉搜索树,用了半天时间实现了树的基本功能后,发现我的二叉树打印方法还是停留在简单的逐行打印,此时的效果图如下:
一行的每两个数值分别对应上一行一个数值的左右孩子,用星号表示空。无疑这种表示方法十分鸡肋,利用人工点数的方式确定节点的左右孩子,实在不方便调试和扩展功能,如果节点多了可能还会造成开发者白内障,危害极大。
出于开发效率和个人身体健康考虑,我觉得我的程序应该可以有一种直观的二叉搜索树显示方式,比如树状打印就是很好的方式,百度浏览了一番找不到前辈们的代码,估计不怕麻烦用C语言写这个的人比较少。既然这样,那就自己动手,写一个二叉搜索树的树状显示函数,冲!
ps:
本程序用MacOS系统下的Xcode编译器开发,未使用windows下的API,整颗树状图都是用空格移动坐标进行逐行打印,具有不错的兼容性,男女老少皆可食用。
正文分割线
先上实现效果图:
接下来就是大概的实现方法:
可以看到效果图中除了数值和括号主要用到的符号就是竖线和下划线,但是在写这个方法的初期我们可以先忽略下划线和竖线,我们可以首先实现数值打印,让节点的值在控制台中对应的坐标中显示,如图:
开始的这一步想了挺久,最后想到数值在中序遍历序列中的位置既可以用来确定数值的横坐标,如果观察上面的图应该也可以发现,数值的横坐标也是按照从小到达逐渐递增的,而纵坐标则可以通过树的深度来确定,想通这一点,实现上面图中的效果就不难了。
typedef int ElemType;
typedef struct node
{
ElemType key;
struct node *lchild, *rchild;
int height;
}BNode,*BTree;
中序遍历二叉树并储存在数组中:
/*定义全局变量用于确定数组下标,因为使用了递归遍历的方法,
下标很难通过传参的方式确定,所以使用了全局变量,其实可以使用栈结构来储存但是懒于再写栈的代码了。
现在的方法虽然有点影响代码的结构性不过暂时没想到其他方便的方法*/
树的结构体:
int a=0;//全局变量
void saveInTraversal(BTree root,int *term)
{
if(!root)
return;
else
{
saveInTraversal(root->lchild,term);
term[a++]=root->key;
saveInTraversal(root->rchild,term);
}
}
在中序遍历序列中查找某个数值的位置:
/**
*@brief 中序遍历序列中查找某个数值的位置
*@param term 中序遍历序列数组
*@param n 数组长度
*@param x 需要搜索的数值
*/
int findNum(int *term, int x, int n)
{
for(int i=0;i<n;i++)
if(term[i]==x)
return i+1;
return -1;
}
获取节点深度:
int deepth(BTree root)
{
if (!root)
{
return 0;
}
int left=deepth(root->lchild);
int right=deepth(root->rchild);
return left>=right ? left+1:right+1;
}
获取节点的子节点个数:
int count(BTree T,int num)
{
if(!T)
return num;
else
{
num=count(T->lchild,num);
num=count(T->rchild,num);
}
num++;
return num;
}
显示函数(无下划线和竖线):
#define MAX(a,b) ((a)>(b)?(a):(b)) //取两者最大值
#define MAX_DIGITS 4 //二叉树树节点值的最大位数。比如树中最大的节点值为1000,则设为4,假设最大为10000,则应设为5,如果设置的该常量数字比节点最大值位数小,则会导致位置错乱
#define MAX_NODE 100//二叉树树的最大节点树目
void display(BTree root)
{
int absotiveDistance[2];//绝对距离,[1]表示上一个兄弟节点,[0]-[1]用于计算节点的相对距离
int array[MAX_NODE]={
0};//用于储存搜索二叉树的中序遍历序列
int relativeDistance=0;//相对距离
//定义标志节点N,节点的子孩子为空时用于占位识别
BTree N;
N=(BTree)malloc(sizeof(BNode));
N->key=-1;
N->lchild=NULL;
N->rchild=NULL;
N->height=0;
int deep=deepth(root);
saveInTraversal(root, array);
//临时变量,用于层序遍历
int k=0;
int j=1;
int n=1;
BTree term[MAX_NODE]={
NULL};//指针数组,储存树节点,用于层序遍历
term[0]=root;
while(n!=deep+1)
{
absotiveDistance[0]=0;
absotiveDistance[1]=0;
if(term[k]->lchild!=NULL&&term[k]->lchild!=N)
term[j++]=term[k]->lchild;
else
term[j++]=N;
if(term[k]->rchild!=NULL&&term[k]->rchild!=N)
term[j++]=term[k]->rchild;
else
term[j++]=N;
k++;
if(k==pow(2,n)-1)
{
for(int i=pow(2,n-1)-1;i<k;i++)
{
absotiveDistance[0]=findNum(array, term[i]->key, count(root, 0))*MAX_DIGITS;
if(absotiveDistance[0]==-MAX_DIGITS