1.在二叉树中增加结点
方法1:遍历
/*
功能:向二叉树中插入新的结点
参数:
root:根结点的地址
value:需要插入的结点的数据
返回值:
根结点的地址
*/
BSTree* insert_node(BSTree* root,ElemType value)
{
//1.先创建一个新的结点
BSTree* new_node = malloc(sizeof(BSTree));
new_node->data=value;
new_node->left=NULL;
new_node->right=NULL;
//2.找到正确的插入位置,并进行插入
BSTree* p = root;//遍历指针
//从无到有
if(root==NULL)
{
root = new_node;
}
//从少到多
else
{
while(1)
{
//需要插入的数据比当前根结点的数据小
//则往当前根结点的左子树中搜索空位进行插入
if(value < p->data)
{
if(p->left == NULL)//找到空位了
{
p->left = new_node;
break;
}
else//如果该结点已经存在左孩子,则继续往下找
{
p=p->left;
}
}
//需要插入的数据比当前根结点的数据大
//则往当前根结点的右子树中搜索空位进行插入
else if(value > p->data)
{
if(p->right == NULL)//找到空位了
{
p->right = new_node;
break;
}
else//如果该节点已经存在右孩子,则继续往下找
{
p=p->right;
}
}
else//相等
{
printf("需要进行插入的数据有误,已存在该数据,无法再次插入\n");
break;
}
}
}
return root;
}
方法2:递归
/*
功能:递归向二叉树中插入新的结点
参数:
root:根结点的地址
value:需要插入的结点的数据
返回值:
根结点的地址
*/
BSTree* digui_insert_node(BSTree* root,ElemType value)
{
//1.先创建一个新的结点
BSTree* new_node = malloc(sizeof(BSTree));
new_node->data=value;
new_node->left=NULL;
new_node->right=NULL;
//从无到有
if(root==NULL)
{
root = new_node;
return root;
}
//从少到多
if(value < root->data)
{
root->left = digui_insert_node(root->left,value);
}
if(value > root->data)
{
root->right = digui_insert_node(root->right,value);
}
return root;
}
2.从二叉树中删除结点
/*
功能:删除树中的结点
参数:
value--需要删除的结点的值
root--树的根结点
返回值:
根结点的地址
*/
BSTree* delete_node(BSTree* root,ElemType value)
{
BSTree* p = root;//找到待删除的结点
BSTree *q = NULL;//找到待删除结点的父结点
//1.查找需要删除的结点的位置
while(p!=NULL)
{
if(p->data == value)//找到了
{
break;
}
else if(value > p->data)//往p的右子树找
{
q = p;//q保存p作为父节点
p = p->right;
}
else if(value < p->data)//往p的左子树找
{
q = p;//q保存p作为父节点
p = p->left;
}
}
//2.删除操作
//没找到
if(p == NULL)
{
printf("没有在二叉树中找到值为%d的结点\n",value);
return root;
}
//找到了
//case1:被删除的结点是叶子结点,直接删除即可
if(p->left == NULL && p->right ==NULL)//p没有孩子
{
if(p == root)//p是根结点
{
free(p);
return NULL;
}
if(p == q->right)//p是q的右孩子
{
q->right = NULL;//断开与需要删除的结点的连接
free(p);
}
else if(p == q->left)//p是q的左孩子
{
q->left = NULL;//断开与需要删除的结点的连接
free(p);
}
}
//case2:被删除的结点p,只有一个孩子结点
//只有左孩子结点,则只需要把待删除的结点p的左孩子与它的父节点q连接,再删除p
//只有右孩子结点,则只需要把待删除的结点p的右孩子与它的父节点q连接,再删除p
else if(p->left == NULL || p->right == NULL)
{
if(p->right !=NULL)//p只有一个右孩子
{
if(p == root)//p是根结点
{
root = p->right;//p的右孩子变成新的根结点
p->right = NULL;
free(p);
}
else if(p == q->right)//p是q的右孩子
{
q->right = p->right;
p->right = NULL;
free(p);
}
else if(p == q->left)//p是q的左孩子
{
q->left = p->right;
p->right = NULL;
free(p);
}
}
else if(p->left !=NULL)//p只有左孩子
{
if(p == root)//p是根结点
{
root = p->left;//p的左孩子变成新的根结点
p->left = NULL;
free(p);
}
else if(p == q->left)//p是q的左孩子
{
q->left = p->left;
p->left = NULL;
free(p);
}
else if(p == q->right)//p是q的右孩子
{
q->right = p->left;
p->left = NULL;
free(p);
}
}
}
//case3:被删除的结点p,有左孩子和右孩子
//从待删除的结点的左子树中查找一个最大值或者从它的右子树中找到一个最小值
//将找到的左子树的最大值或右子树的最小值中的数据与p交换
//删除查到的那个最大值或最小值结点
else if(p->left !=NULL && p->right !=NULL)
{
BSTree* p2 = p->left;//p2是p左子树的根结点
BSTree* q2 =NULL;//q2用来保存p2的父节点
while(p2->right != NULL)
{
q2 = p2;
p2 = p2->right;
}
//将找到的左子树的最大值或右子树的最小值中的数据与p交换
//p的左子树中最大值所在的结点就是p2;
if(p2 == p->left)
{
ElemType temp = p2->data;
p2->data = p->data;
p->data = temp;
//删除查到的那个最大值或最小值结点
p->left = p2->left;
p2->left = NULL;
free(p2);
}
else//p的左子树p2中包含右子树
{
ElemType temp = p2->data;
p2->data = p->data;
p->data = temp;
//删除查到的那个最大值或最小值结点
q2->right = p2->left;
p2->left = NULL;
free(p2);
}
}
return root;
}
3.在二叉树中查找数据
/*
功能:在二叉树中查找数据
参数:
root:二叉树根结点的地址
value:要查找的数据
返回值:
成功返回该数据结点的地址
失败返回NULL
*/
BSTree* search(BSTree* root,ElemType value)
{
if(root == NULL || root->data == value)
{
return root;
}
if(value > root->data)
{
return search(root->right,value);
}
return search(root->left,value);
}
4.二叉树的先序、中序、后序、层序遍历
/*
功能:递归实现二叉树的先序遍历:根、左、右
参数:
root: 根结点地址
*/
void pre_order(BSTree* root)
{
if(root == NULL)
{
return ;
}
//1.先访问根结点
printf("%d ",root->data);
//2.再按照先序遍历的顺序区访问根结点的左子树
pre_order(root->left);
//3.再按照先序遍历的顺序去访问根结点的右子树
pre_order(root->right);
}
/*
功能:递归实现二叉树的中序遍历:左、根、右
参数:
root: 根结点地址
*/
void mid_order(BSTree* root)
{
if(root == NULL)
{
return ;
}
//1.先按照遍历顺序访问根结点的左孩子结点
mid_order(root->left);
//2.再访问根结点
printf("%d ",root->data);
//3.再按照先序遍历的顺序去访问根结点的右子树
mid_order(root->right);
}
/*
功能:递归实现二叉树的后序遍历:左、右、根
参数:
root: 根结点地址
*/
void post_order(BSTree* root)
{
if(root == NULL)
{
return ;
}
//1.先按照遍历顺序访问根结点的左孩子结点
post_order(root->left);
//2.再按照先序遍历的顺序去访问根结点的右子树
post_order(root->right);
//3.再访问根结点
printf("%d ",root->data);
}
/*
功能:实现层序遍历
参数:
root:根结点地址
*/
void lever_order(BSTree* root)
{
//初始化队列
queue* p = init_queue();
//1.把树的根结点入队
push_queue(p,root);
BSTree* q = NULL;//二叉树的遍历指针
while(p->num!=0)
{
//2.获取队头元素,并进行打印
q = get_front(p);
printf("%d ",q->data);
//3.判断当前队头元素是否存在左右孩子,如果存在左右孩子,则将其入队
if(q->left!=NULL)
{
push_queue(p,q->left);
}
if(q->right!=NULL)
{
push_queue(p,q->right);
}
//出队
pop_queue(p);
}
}
二叉树的层序遍历需要使用一个队列辅助完成,其算法如下:
step1:
把树的根结点入队
step2:
获取队头元素,并进行打印
step3:
判断当前队头元素是否存在左、右孩子。如果存在左、右孩子,则将其入队
step4:
出队
重复上面的过程
2
、
3
、
4
步
5.完整源码
5.1 BSTree.c文件(树的功能实现文件)
#include "queue.h"
/*
功能:向二叉树中插入新的结点
参数:
root:根结点的地址
value:需要插入的结点的数据
返回值:
根结点的地址
*/
BSTree* insert_node(BSTree* root,ElemType value)
{
//1.先创建一个新的结点
BSTree* new_node = malloc(sizeof(BSTree));
new_node->data=value;
new_node->left=NULL;
new_node->right=NULL;
//2.找到正确的插入位置,并进行插入
BSTree* p = root;//遍历指针
//从无到有
if(root==NULL)
{
root = new_node;
}
//从少到多
else
{
while(1)
{
//需要插入的数据比当前根结点的数据小
//则往当前根结点的左子树中搜索空位进行插入
if(value < p->data)
{
if(p->left == NULL)//找到空位了
{
p->left = new_node;
break;
}
else//如果该结点已经存在左孩子,则继续往下找
{
p=p->left;
}
}
//需要插入的数据比当前根结点的数据大
//则往当前根结点的右子树中搜索空位进行插入
else if(value > p->data)
{
if(p->right == NULL)//找到空位了
{
p->right = new_node;
break;
}
else//如果该节点已经存在右孩子,则继续往下找
{
p=p->right;
}
}
else//相等
{
printf("需要进行插入的数据有误,已存在该数据,无法再次插入\n");
break;
}
}
}
return root;
}
/*
功能:递归向二叉树中插入新的结点
参数:
root:根结点的地址
value:需要插入的结点的数据
返回值:
根结点的地址
*/
BSTree* digui_insert_node(BSTree* root,ElemType value)
{
//1.先创建一个新的结点
BSTree* new_node = malloc(sizeof(BSTree));
new_node->data=value;
new_node->left=NULL;
new_node->right=NULL;
//从无到有
if(root==NULL)
{
root = new_node;
return root;
}
//从少到多
if(value < root->data)
{
root->left = digui_insert_node(root->left,value);
}
if(value > root->data)
{
root->right = digui_insert_node(root->right,value);
}
return root;
}
/*
功能:创建一个二叉树
返回值:返回二叉树的根节点地址
*/
BSTree* Create_sort_tree()
{
BSTree* root=NULL;//根结点
ElemType value;
//从终端接收数据,并将数据存储到节点中
//用于构建一个二叉排序树
printf("请输入二叉排序树的数据:\n");
while(1)
{
scanf("%d",&value);
if(value == 0)
break;
//往二叉树添加结点
root = insert_node(root,value);
}
return root ;
}
/*
功能:在二叉树中查找数据
参数:
root:二叉树根结点的地址
value:要查找的数据
返回值:
成功返回该数据结点的地址
失败返回NULL
*/
BSTree* search(BSTree* root,ElemType value)
{
if(root == NULL || root->data == value)
{
return root;
}
if(value > root->data)
{
return search(root->right,value);
}
return search(root->left,value);
}
/*
功能:递归实现二叉树的先序遍历:根、左、右
参数:
root: 根结点地址
*/
void pre_order(BSTree* root)
{
if(root == NULL)
{
return ;
}
//1.先访问根结点
printf("%d ",root->data);
//2.再按照先序遍历的顺序区访问根结点的左子树
pre_order(root->left);
//3.再按照先序遍历的顺序去访问根结点的右子树
pre_order(root->right);
}
/*
功能:递归实现二叉树的中序遍历:左、根、右
参数:
root: 根结点地址
*/
void mid_order(BSTree* root)
{
if(root == NULL)
{
return ;
}
//1.先按照遍历顺序访问根结点的左孩子结点
mid_order(root->left);
//2.再访问根结点
printf("%d ",root->data);
//3.再按照先序遍历的顺序去访问根结点的右子树
mid_order(root->right);
}
/*
功能:递归实现二叉树的后序遍历:左、右、根
参数:
root: 根结点地址
*/
void post_order(BSTree* root)
{
if(root == NULL)
{
return ;
}
//1.先按照遍历顺序访问根结点的左孩子结点
post_order(root->left);
//2.再按照先序遍历的顺序去访问根结点的右子树
post_order(root->right);
//3.再访问根结点
printf("%d ",root->data);
}
/*
功能:实现层序遍历
参数:
root:根结点地址
*/
void lever_order(BSTree* root)
{
//初始化队列
queue* p = init_queue();
//1.把树的根结点入队
push_queue(p,root);
BSTree* q = NULL;//二叉树的遍历指针
while(p->num!=0)
{
//2.获取队头元素,并进行打印
q = get_front(p);
printf("%d ",q->data);
//3.判断当前队头元素是否存在左右孩子,如果存在左右孩子,则将其入队
if(q->left!=NULL)
{
push_queue(p,q->left);
}
if(q->right!=NULL)
{
push_queue(p,q->right);
}
//出队
pop_queue(p);
}
}
/*
功能:删除树中的结点
参数:
value--需要删除的结点的值
root--树的根结点
返回值:
根结点的地址
*/
BSTree* delete_node(BSTree* root,ElemType value)
{
BSTree* p = root;//找到待删除的结点
BSTree *q = NULL;//找到待删除结点的父结点
//1.查找需要删除的结点的位置
while(p!=NULL)
{
if(p->data == value)//找到了
{
break;
}
else if(value > p->data)//往p的右子树找
{
q = p;//q保存p作为父节点
p = p->right;
}
else if(value < p->data)//往p的左子树找
{
q = p;//q保存p作为父节点
p = p->left;
}
}
//2.删除操作
//没找到
if(p == NULL)
{
printf("没有在二叉树中找到值为%d的结点\n",value);
return root;
}
//找到了
//case1:被删除的结点是叶子结点,直接删除即可
if(p->left == NULL && p->right ==NULL)//p没有孩子
{
if(p == root)//p是根结点
{
free(p);
return NULL;
}
if(p == q->right)//p是q的右孩子
{
q->right = NULL;//断开与需要删除的结点的连接
free(p);
}
else if(p == q->left)//p是q的左孩子
{
q->left = NULL;//断开与需要删除的结点的连接
free(p);
}
}
//case2:被删除的结点p,只有一个孩子结点
//只有左孩子结点,则只需要把待删除的结点p的左孩子与它的父节点q连接,再删除p
//只有右孩子结点,则只需要把待删除的结点p的右孩子与它的父节点q连接,再删除p
else if(p->left == NULL || p->right == NULL)
{
if(p->right !=NULL)//p只有一个右孩子
{
if(p == root)//p是根结点
{
root = p->right;//p的右孩子变成新的根结点
p->right = NULL;
free(p);
}
else if(p == q->right)//p是q的右孩子
{
q->right = p->right;
p->right = NULL;
free(p);
}
else if(p == q->left)//p是q的左孩子
{
q->left = p->right;
p->right = NULL;
free(p);
}
}
else if(p->left !=NULL)//p只有左孩子
{
if(p == root)//p是根结点
{
root = p->left;//p的左孩子变成新的根结点
p->left = NULL;
free(p);
}
else if(p == q->left)//p是q的左孩子
{
q->left = p->left;
p->left = NULL;
free(p);
}
else if(p == q->right)//p是q的右孩子
{
q->right = p->left;
p->left = NULL;
free(p);
}
}
}
//case3:被删除的结点p,有左孩子和右孩子
//从待删除的结点的左子树中查找一个最大值或者从它的右子树中找到一个最小值
//将找到的左子树的最大值或右子树的最小值中的数据与p交换
//删除查到的那个最大值或最小值结点
else if(p->left !=NULL && p->right !=NULL)
{
BSTree* p2 = p->left;//p2是p左子树的根结点
BSTree* q2 =NULL;//q2用来保存p2的父节点
while(p2->right != NULL)
{
q2 = p2;
p2 = p2->right;
}
//将找到的左子树的最大值或右子树的最小值中的数据与p交换
//p的左子树中最大值所在的结点就是p2;
if(p2 == p->left)
{
ElemType temp = p2->data;
p2->data = p->data;
p->data = temp;
//删除查到的那个最大值或最小值结点
p->left = p2->left;
p2->left = NULL;
free(p2);
}
else//p的左子树p2中包含右子树
{
ElemType temp = p2->data;
p2->data = p->data;
p->data = temp;
//删除查到的那个最大值或最小值结点
q2->right = p2->left;
p2->left = NULL;
free(p2);
}
}
return root;
}
void main()
{
//创建一棵二叉排序树
BSTree* root = Create_sort_tree();
printf("先序遍历:");
pre_order(root);
printf("\n");
printf("中序遍历:");
mid_order(root);
printf("\n");
printf("后序遍历:");
post_order(root);
printf("\n");
printf("层序遍历:");
lever_order(root);
printf("\n");
BSTree*p = delete_node(root,8);
printf("删除后先序遍历的结果:");
pre_order(root);
printf("\n");
}
5.2queue.c(层序遍历辅助队列,如果不用层序遍历可以不要)
#include "queue.h"
/*
功能:新结点初始化
参数:
value--二叉树结点
返回值:队列的地址
*/
Queue* init_data_queue(BSTree* value)
{
Queue* new_node=malloc(sizeof(Queue));
new_node->data=value;
new_node->next=NULL;
return new_node;
}
/*
功能:队列头结点初始化(存储队列属性信息)
返回值:队列首地址
*/
queue* init_queue()
{
queue* p=malloc(sizeof(queue));
p->front=NULL;
p->rear=NULL;
p->num=0;
return p;
}
/*
功能:入队(尾插入队)
参数:
p--队列首地址
value--待插入的二叉树结点
*/
void push_queue(queue* p,BSTree* value)
{
Queue* q = init_data_queue(value);//初始化待插入结点
if(p->front == NULL)
{
p->front = q;
p->rear = q;
p->num++;
}
else
{
p->rear->next=q;
p->rear=q;
p->num++;
}
}
/*
功能:出队
参数:p--队列首地址
*/
void pop_queue(queue* p)
{
if(p->num==0)
{
printf("队列已空,无法出队\n");
return ;
}
else if(p->front->next == NULL)
{
Queue* q = p->front;
p->front = NULL;
p->rear = NULL;
p->num--;
free(q);
}
else
{
Queue* q=p->front;
p->front=p->front->next;
q->next=NULL;
free(q);
p->num--;
}
}
/*
功能:获取队头元素结点
参数:队列地址
返回值:队头元素的结点
*/
BSTree* get_front(queue* p)
{
if(p->num==0)
return NULL;
return p->front->data;//队列数据域的类型是BSTree*
}
/*
功能: 销毁一个队列
参数:
queue: 队列的头结点的地址
返回值:
NULL
*/
queue* destory_queue(queue* queue)
{
Queue* p = queue->front; //遍历整个队列
Queue* p_next = NULL; //用来保存此时待删除结点的下一个结点的地址
while(p != NULL)
{
p_next = p->next; //保存此时待删除结点的下一个结点的地址
p->next = NULL;
free(p);
p = p_next; //继续往后遍历
}
queue->front = NULL;
queue->rear = NULL;
queue->num = 0;
free(queue);
queue = NULL;
return queue;
}
5.3queue.h内含所有函数的声明以及结构体
#ifndef __QUEUE_H__
#define __QUEUE_H__
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct BSTree
{
ElemType data;//数据域
struct BSTree* left;//左孩子指针
struct BSTree* right;//右孩子指针
}BSTree;
typedef struct Queue
{
BSTree* data;//数据域保存二叉树的结点
struct Queue* next;//指针域
}Queue;
typedef struct queue
{
Queue* front;
Queue* rear;
ElemType num;
}queue;
Queue* init_data_queue(BSTree* value);
queue* init_queue();
void push_queue(queue* p,BSTree* value);
void pop_queue(queue* p);
BSTree* get_front(queue* p);
queue* destory_queue(queue* queue);
#endif