目录
一、二叉树的遍历
1.先序遍历 (根结点---左结点---右结点)
A-B-D-E-G-C-F-F-I
2.中序遍历 (左节点---根结点---右节点)
D-B-G-E-A-C-H-F-I
3.后续遍历 (左结点---右节点---根结点)
D-G-E-B-H-I-F-C-A
二、二叉树程序
1.创建结构体
struct score_st
{
int id;
char name[NAMESIZE];
int math;
};
struct node_st
{
struct score_st data;
struct node_st *l,*r;
};
2.插入结点
int insert(struct node_st **root, struct score_st *data)
{
struct node_st *node;
if(*root == NULL) //当root指向的指针为空
{
node = malloc(sizeof(*node)); //创建一个结点
if(node == NULL)
return -1;
node->data = *data; //将要插入的数据赋值给node
node->l = node->r = NULL; //结点的做指针和右指针设为NULL
*root = node; //将结点的地址保存到root指向的指针中
return 0;
}
if(data->id <= (*root)->data.id) //当树不为空时,比较id的值,id小的在树的左侧
return insert(&(*root)->l,data);
return insert(&(*root)->r,data); //id大的在树的右侧
}
2.找到某个结点,并返回结点中的数据
struct score_st *find(struct node_st *root, int id)
{
if(root == NULL)
return NULL;
if(root->data.id == id) //如果要找的id和结点中的id相等,返回数据
return &root->data;
if(id < root->data.id) //如果要找的id小于结点中的id,再递归调用找左结点
return find(root->l,id);
return find(root->r,id); //如果要找的id大于结点中的id,再递归调用找右结点
}
3.左偏 遍历输出
static void draw_(struct node_st *root,int level)
{
int i;
if(root == NULL) //root为NULL直接结束函数
return ;
draw_(root->r,level+1); //递归调用draw,指向右子树,level+1
for(i = 0 ; i < level; i++) //输出level个空格
printf(" ");
print_s(&root->data);
draw_(root->l,level+1); 递归调用draw,指向左子树,level+1
}
void draw(struct node_st *root)
{
draw_(root,0);
}
4.平衡二叉树
static int get_num(struct node_st *root) //返回树的结点个数
{
if(root == NULL)
return 0;
return get_num(root->l) + 1 + get_num(root->r);//递归调用返回结点个数
}
static struct node_st *find_min(struct node_st *root)
{
if(root->l == NULL) //如果root的左结点为NULL,将root返回
return root;
return find_min(root->l); //递归调用查找左结点,当左结点为NULL,将这个结点返回
}
static void turn_left(struct node_st **root)
{
struct node_st *cur = *root; //定义一个指针,指向*root指向的位置
*root = cur->r; //*root指向cur的右结点
cur->r = NULL; //cur的右结点赋值为NULL
find_min(*root)->l = cur; //找到最小的结点,将cur插入到最小结点的左结点
// draw(tree);
}
static struct node_st *find_max(struct node_st *root)
{
if(root->r == NULL) //如果root的左结点为NULL,将root返回
return root;
return find_max(root->r); //递归调用查找右结点,当右结点为NULL,将这个结点返回
}
static void turn_right(struct node_st **root)
{
struct node_st *cur = *root; //定义一个指针,指向*root指向的位置
*root = cur->l; //*root指向cur的左结点
cur->l = NULL; //cur的左结点赋值为NULL
find_max(*root)->r = cur; //找到最大的结点,将cur插入到最大结点的右结点
// draw(tree);
}
void balance(struct node_st **root)
{
int sub;
if(*root == NULL)
return ;
while(1)
{
sub = get_num((*root)->l) - get_num((*root)->r); //得到根结点左子树和右子树的结点差值
if(sub >= -1 && sub <= 1) //两边的结点数差值如果是-1 0 1时结束循环
break;
if(sub < -1) //如果差值小于-1,向左旋
turn_left(root);
else //如果差值大于1,向右旋
turn_right(root);
}
balance(&(*root)->l); //递归调用,平衡左子树
balance(&(*root)->r); //递归调用,平衡右子树
}
5.遍历
1)先序遍历
void travel(struct node_st *root)
{
if(root == NULL)
return ;
print_s(&root->data);
travel(root->l);
travel(root->r);
}
2)中序遍历
void travel(struct node_st *root)
{
if(root == NULL)
return ;
travel(root->l);
print_s(&root->data);
travel(root->r);
}
3)后序遍历
void travel(struct node_st *root)
{
if(root == NULL)
return ;
travel(root->l);
travel(root->r);
print_s(&root->data);
}
4)按层遍历
void travel(struct node_st *root)
{
QUEUE *qu;
struct node_st *cur;
qu = queue_create(sizeof(struct node_st *)); //创建队列
queue_en(qu, &root); //根结点入队
while(1)
{
if(queue_de(qu, &cur) != 0) //如果删除回显不成功,则结束循环
break;
print_s(&cur->data); //输出回显指针指向的数据
if(cur->l != NULL) //指针左结点不为NULL,则入队
queue_en(qu,&cur->l);
if(cur->r != NULL) //指针右结点不为NULL,则入队
queue_en(qu,&cur->r);
}
queue_destroy(qu);
}
6.删除结点
void delete(struct node_st **root, int id)
{
struct node_st **node = root;
struct node_st *cur;
while( (*node) != NULL && (*node)->data.id != id )//查找要删除的结点
{
if( id < (*node)->data.id ) //如果想要删除的id小于结点中的id,让指针指向结点的左结点
node = &(*node)->l;
else
node = &(*node)->r; //如果想要删除的id小于结点中的id,让指针指向结点的左结点
}
if(*node == NULL) //没找到直接返回
return ;
cur = *node;
if(cur->l == NULL) //如果找到的结点的左子树为NULL,则直接将*node指向cur的右结点
*node = cur->r;
else
{
*node = cur->l; //不为NULL,则直接将*node指向cur的左结点
find_max(cur->l)->r = cur->r; //将找到的结点的右子树插入到*node的右子树的最后面
}
free(cur);
}