#include <stdio.h>
#include <stdlib.h>
/*创建一颗 搜索二叉树 结构体*/
typedef struct TreeNode{
int data;
struct TreeNode *leftTree;
struct TreeNode *rightTree;
}TreeNode;
/*中序递归遍历*/ /* 递归的本质是压栈 */
void mid_travel(TreeNode *Node)
{
if(Node) /*如果节点不为空,就进入*/
{
mid_travel(Node->leftTree);
printf("%d ",Node->data);
mid_travel(Node->rightTree);
}
}
/*往树中插入数据*/
void insertNode(TreeNode **r,int data)
{
TreeNode *t = (*r);
if((*r) == NULL) /*刚开始是空树;创建树*/
{
/*申请一个空间,用来存储根节点*/
*r = (TreeNode *)malloc(sizeof(TreeNode));
/*初始化根节点*/
(*r)->data = data;
(*r)->leftTree = (*r)->rightTree = NULL;
}
else /*如果不是空树,插入子树*/
{
/*因为下面不在涉及指向问题了,所以不再使用(*r),转而用t 代替*/
while(1)
{
/*搜索二叉树,必须按照一定的顺序插入*/
if(data > t->data) /*大于,在右*/
{
if(t->rightTree == NULL)
{
/*先创建一块空间,然后初始化 和创建根节点的方法一样*/
t->rightTree = (TreeNode *)malloc(sizeof(TreeNode));
t->rightTree->data = data;
t->rightTree->leftTree = t->rightTree->rightTree = NULL;
break;
}
/*如果不为空,指向下一个节点,然后继续往下执行。如果data <= t->data
执行下面的。如果不是,通过wile(1),再执行上面的*/
t = t->rightTree;
}
else
{
if(t->leftTree == NULL)
{
/*创建内存,并初始化*/
t->leftTree = (TreeNode *)malloc(sizeof(TreeNode));
t->leftTree->data = data;
t->leftTree->leftTree = t->leftTree->rightTree = NULL;
break;
}
t = t->leftTree;
}
}
}
}
/*搜索二叉树 添加节点 的 递归写法*/
void inser_node(TreeNode **r,int data)
{
if((*r)==NULL)
{
/*创建树根*/
(*r) = (TreeNode*)malloc(sizeof(TreeNode));
(*r)->data = data;
(*r)->leftTree = (*r)->rightTree = NULL;
}
else
{
if(data > (*r)->data)
inser_node(&(*r)->rightTree,data);
else
inser_node(&(*r)->leftTree,data);
}
}
/*搜索二叉树节点 非递归*/
TreeNode * searchNode(TreeNode *Node,int find)
{
while(Node)
{
if(find == Node->data)
return Node;
else if(find > Node->data)
Node = Node->rightTree;
else
Node = Node->leftTree;
}
/*没有找到。返回NULL*/
return NULL;
}
/*搜索二叉树节点 递归写法*/
TreeNode *search_Node(TreeNode* Node,int data)
{
if(Node)
{
if(data == Node->data)
return Node;
else if(data > Node->data) /*分情况递归,加return*/
return search_Node(Node->rightTree,data);
else
return search_Node(Node->leftTree,data);
}
return NULL;
}
/*搜索二叉树的最大节点 找最右*/
TreeNode * max_Node(TreeNode *Node)
{
if(Node)
{
while(Node->rightTree)
{
Node = Node->rightTree;
}
return Node;
}
/*如果没找到,返回NULL*/
return NULL;
}
/*搜索二叉树的最小节点 找最左*/
TreeNode *minNode(TreeNode *Node)
{
if(Node)
{
while(Node->leftTree)
{
Node = Node->leftTree;
}
return Node;
}
return NULL;
}
/*搜索二叉树的当前节点的父节点*/
TreeNode *parent_Node(TreeNode *root,TreeNode *child)
{
/*递归中的静态变量*/
static TreeNode *parent = NULL;
// TreeNode *parent = NULL;
if(root)
{
if(root->leftTree == child || root->rightTree == child)
parent = root;
else
{
parent_Node(root->leftTree,child);
parent_Node(root->rightTree,child);
}
}
return parent;
}
/*删除二叉树的节点*/
/*删除逻辑:分三种情况删除:
*第一种情况:若为叶子节点,直接删除( 根叶子节点 要单独处理)
*第二种情况:若该节点有一个子节点,左节点或右节点 。找到他的父节点,
*让父节点指向左节点或右节点(若该节点为根,要单独处理 )
*第三种情况:有两个子节点 */
void delNode(TreeNode **r,TreeNode *del)
{
if((*r)==NULL || del == NULL) return ;
TreeNode *parent; /*父节点*/
TreeNode *root = *r; /*定义变量,用来存储跟节点的地址*/
TreeNode *minRight; /*给两个子节点的情况使用*/
/*情况一:叶子节点的情况 分为 普通叶子节点 和 跟叶子节点 的情况*/
if(del->leftTree==NULL && del->rightTree==NULL)
{
/* 跟叶子节点 */
if((*r) == del)
{
free(root);
(*r)=NULL;
/*return一定要加,否则就要继续执行了*/
return ;
}
/*其他跟叶子节点*/
else
{
parent = parent_Node(root,del);
if(parent->leftTree == del)
parent->leftTree = NULL;
else
parent->rightTree = NULL;
free(del);
}
}
/*第二种情况 只有一个节点的情况 先分析只有左节点的情况*/
else if(del->leftTree != NULL && del->rightTree == NULL)
{
if((*r) == del) /*再分成两种情况 删除节点是 根节点 和 非根节点*/
{
(*r) = del->leftTree/*或者是这样root->leftTree*/;
free(del/*root*/);
return;
}
else
{
/*找到父节点*/
parent = parent_Node(root,del);
/*确定要删除的节点是父节点的 左节点 还是 右节点*/
if(parent->leftTree == del)
parent->leftTree = del->leftTree;
else
parent->rightTree = del->leftTree;
free(del);
return;
}
}
/*再分析第二种情况中,只有右节点的情况*/
else if(del->leftTree == NULL && del->rightTree != NULL)
{
/*方法和上面一样*/
if(root == del)
{
(*r) = del->rightTree;
free(del);
return;
}
/*找到父节点*/
parent = parent_Node(root,del);
if(parent->leftTree == del)
parent->leftTree = del->leftTree;
else
parent->rightTree = del->leftTree;
free(del);
}
/*第三种情况 左右节点都有*/
else
{
/*通常情况下(也就是他的右面还有分支的情况),找他右面最小的节点(这个节点一定是没有左节点,右节点可有可无),
* 将这个节点和待删除节点互换
* 另外,这个节点一定有父节点(是他的右上节点),将父节点直接和最小节点的右节点连接*/
minRight = minNode(del->rightTree);
del->data = minRight->data;
parent = parent_Node(root,minRight);
if(minRight != del->rightTree)/*这种情况的判断*/
parent->leftTree = minRight->rightTree;
/*特殊情况,右侧是一条线的情况 此时,parent = pdel */
else
parent->rightTree = minRight->rightTree;
/*删除最小的*/
free(minRight);
}
}
/*按照中序遍历的顺序,输出搜索二叉树的当前节点的的下一个节点*/
/*销毁树 递归实现*/
void destroy_tree(TreeNode *root)
{
if(root)
{
destroy_tree(root->leftTree);
destroy_tree(root->rightTree);
free(root);
}
}
int main(void)
{
/*不赋初值,运行没效果*/
TreeNode *root = NULL;
int data[]={6,2,8,1,5,3,4};
int i = 0,num =7;
for(i=0;i<num;i++)
{
inser_node(&root,data[i]);
}
/*中序遍历*/
mid_travel(root);
TreeNode *findB;
TreeNode *min;
TreeNode *max;
TreeNode *par;
/*递归查找*/
findB = searchNode(root,2);
if(findB)
printf("\nfind=%d \n ",findB->data);
else
printf("\n not find \n");
/*搜索最小节点*/
min = minNode(root);
printf("min=%d;\n",min->data);
/*搜索最大节点*/
max = max_Node(root);
printf("max=%d;\n",max->data);
/*搜索二叉树的当前节点的父节点*/
par = parent_Node(root,findB);
printf("parent=%d \n ",par->data);
/*删除二叉树的节点*/
delNode(&root,findB);
/*中序遍历*/
mid_travel(root);
return 0;
}
搜索二叉树节点的查找与删除 (C语言)
最新推荐文章于 2022-08-14 11:52:00 发布