一、知识点
1.树形结构 : 结构定义+结构操作
根节点是全集(必须先从根开始解决) 节点是集合(事件) 边是关系(指向关系)
(链表是树的特例,指针域的元素个数)
树的(深度:从上向下) (高度:从下向上)
节点的深度和高度 节点的度(带了几个子孩子) 节点数量=变数+1
节点的度:一个节点含有的子树的个数,叫做该节点的度
叶节点和终端节点:度为零的节点
双亲结点或父节点:C为G的父节点
孩子节点或子节点:G为C的子节点
兄弟节点:拥有相同父节点的节点称为兄弟节点
树的度:一棵树中最大的节点的度称为树的度
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推
树的高度或深度:树中节点的最大层次
祖先:从根到该节点所经分支上的所有节点(根是所有节点的祖先)
森林:由m(m>0)棵互不相交的树的集合称为森林
2.二叉树:
节点的最多为二
a.度为0的节点比度为二的节点多一个
一个度为二的结点等价于一次合并
度为0的节点视为独立的集合,n个集合的合并需要n-1次操作
故 n1=n2 - 1
任何其他树都可以转化为二叉树
b.左孩子右兄弟表示法
左边放子节点,右边放兄弟节点
n叉树===二叉树(未确定性问题转化为确定性问题,无需管n)
c.遍历方式
前序遍历 :根->左->右
中序遍历 :左->根->右
后序遍历 :左->右->根
d.完全二叉树(comple binary tree)
只有右节点的右节点的。。。是缺的
1.一层一层编号(左孩子为偶数 2*i ,右孩子为奇数 2*i+1 )
2.连续编号===》可以用连续空间存储( 数 组 )
3.完全二叉树不是基于记录的(记录所有的数据)
而是基于计算的(记住一个运算规则即可)
***算法/思维优化手段:记录方式转计算方式!!
e.满二叉树(full binary tree)
没有度为1的节点,要么就是度为0要么就是度为2的节点
f.完美二叉树(perfect binary tree)
Tips
二叉树的广义表:【“()”和递归以及树形结构的关系,真实包含关系】
():空树
A/A(): A
A(B,)/A(B):(逗号前左子树,逗号后右子树)
A(B,C):
A(B(,D),C(E))
g.排序二叉树
如果它的左子树不为空,那么左子树上所有节点的值均小于它的根节点的值
如果它的右子树不为空,那么右子树上所有节点的值均大于它的根节点的值
根节点的左子树和右子树均是二叉排序树
(可能退化为链表,所以有平衡二叉树的概念;二叉排序树的中序遍历是从小到大有序的)
二、结构操作:
1.创建新的树
2.创建新的节点
3.插入节点(按照二叉排序树)
4.清空节点
5.清空树
6.前序遍历
7.中序遍历
8.后序遍历
9.输出节点
10.输出树
11.寻找节点(按照二叉排序树)
- 若等于根节点则成功返回
- 如果小于根节点,则查找其左子树
- 否则的话查找其右子树
12.删除节点
删除却可以分为三种不同的情况;
(1)删除的节点刚好是叶子结点(没有子结点)——直接删除
把删除节点置为NULL即可(删除节点的父节点指向NULL)
特例:如果删除节点是root节点,则root置为NULL即可
(2)删除的节点只有左孩子或者只有右孩子,把删除节点的父节点指向删除节点的子结点即可
特例:如果删除节点是root节点,即可认为删除链表的头节点,把第二个节点当作表头即可
Tips:如果24只有右孩子:不用担心24的右孩子会不会比24的父母还大
因为如果24右孩子比24父母(45)还大,那么在建树的时候就会放到45的右孩子上
所以,根的左子树上的所有节点都要比它小
(3)删除的节点既有左孩子又有右孩子,两种删除方法
如果删除的节点有两个子结点,为保证二叉排序树的有序性
需要找到与删除节点键值最接近的两个节点
由排序二叉树的特性知,这两个节点位于删除节点左子树的最右节点,右子树的最左节点
然后将删除节点的父节点指向其中任意一个(例如左子树最右节点,简称替代节点)
让替代节点的右指针指向删除节点的右子树
当替代节点的父节点不是删除节点时,替代节点的左指针指向删除节点的左子树,替代节点的父节点指向替代节点的左子树(替代节点处于最右时没有左子树)
特例1:删除的节点为root
特例2:替代节点的父节点是删除节点
①左子树“上位”,右子树合并到左子树,因为右子树上节点肯定都比左子树上的大,所以把右子树的根接到左子树的最右下角。
②左子树最右下角作为最接近被删节点的节点之一,可以直接替代子树的父母
以上的两种方法都可以作镜像变换,比如左子树最大对应右子树最小
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct Node
{
int val;
struct Node *lchild,*rchild;
} Node; //树的节点
typedef struct Tree
{
int n;//节点个数
Node * root;
} Tree;
Node *getNewNode(int val);
Tree *getNewTree(void);
void clearNode(Node *node);
void clearTree(Tree*tree);
void outputNode(Node *root);
void outputTree(Tree *tree);
Node *insertNode(Node *root,int val,int* ret);
int insert(Tree *tree,int val);
void preorder(Tree *tree);
void preorderNode(Node *root);
void inorderNode(Node *root);
void inorder(Tree *tree);
void postorderNode(Node *root);
void postorder(Tree *tree);
Node *getNewNode(int val)
{
Node *p=(Node*)malloc(sizeof(Node));
p->val = val;
p->lchild = p->rchild = NULL;
return p;
}
Tree *getNewTree(void)
{
Tree *tree = (Tree*)malloc(sizeof(Tree));
tree->n = 0;
tree->root = NULL;
return tree;
}
void clearNode(Node *node)
{
if(node == NULL) return ;
clearNode(node->lchild);
clearNode(node->rchild);
free(node);
return ;
}//用递归去遍历并清除树
void clearTree(Tree*tree)
{
clearNode(tree->root);
free(tree);
return ;
}//
void outputNode(Node *root)
{
if(root == NULL) return ;
printf("%d",root->val);
if(root->lchild == NULL && root->rchild == NULL) return ;
printf("(");
outputNode(root->lchild);
printf(",");
outputNode(root->rchild);
printf(")");
return ;
}
void outputTree(Tree *tree)
{
printf("tree(%d)=",tree->n);
outputNode(tree->root);
return ;
}//转换为广义表
Node *insertNode(Node *root,int val,int* ret)
//二叉排序树,左子树小于根节点小于右节点,中序遍历!!!
{
if(root == NULL)
{
*ret = 1;
return getNewNode(val);//关键点!!!
}
if(root->val == val) return root;//什么都不干
if(root->val > val) root->lchild = insertNode(root->lchild,val,ret);//比当前根节点小插入左侧
else root->rchild = insertNode(root->rchild,val,ret);
return root;
}//用递归方法插入
int insert(Tree *tree,int val)
{
int flag = 0;
tree->root = insertNode(tree->root,val,&flag);
tree->n += flag;//flag为1插入成功,flag为0插入失败
return 1;
}
void preorderNode(Node *root)
{
if(root == NULL) return ;
printf("%d->",root->val);
preorderNode(root->lchild);
preorderNode(root->rchild);
return ;
}
void preorder(Tree *tree)
{
printf("preorder:");
preorderNode(tree->root);
printf("NULL");
printf("\n");
}
void inorderNode(Node *root)
{
if(root==NULL) return ;
inorderNode(root->lchild);
printf("%d->",root->val);
inorderNode(root->rchild);
}
void inorder(Tree *tree)
{
printf("inorder:");
inorderNode(tree->root);
printf("NULL");
printf("\n");
return ;
}
void postorderNode(Node *root)
{
if(root==NULL) return ;
postorderNode(root->lchild);
postorderNode(root->rchild);
printf("%d->",root->val);
}
void postorder(Tree *tree)
{
printf("postorder:");
postorderNode(tree->root);
printf("NULL");
printf("\n");
return ;
}
int main(void)
{
srand(time(NULL));
Tree* tree = getNewTree();
for(int i=0; i<20; i++)
{
int val=rand()%100+1;
insert(tree,val);
outputTree(tree);
printf("\n");
}
printf("\n");
preorder(tree);
inorder(tree);
postorder(tree);
return 0;
}
头晕版本:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct Node
{
int val;
struct Node *lchild,*rchild;
} Node; //树的节点
typedef struct Tree
{
int n;//节点个数
Node * root;
} Tree;
Node *getNewNode(int val);
Tree *getNewTree(void);
void clearNode(Node *node);
void clearTree(Tree*tree);
void outputNode(Node *root);
void outputTree(Tree *tree);
Node *insertNode(Node *root,int val,int* ret);
int insert(Tree *tree,int val);
void preorder(Tree *tree);
void preorderNode(Node *root);
void inorderNode(Node *root);
void inorder(Tree *tree);
void postorderNode(Node *root);
void postorder(Tree *tree);
Node *searchNode1(Tree* tree,int val);
Node *searchNode_Tree(Node* p,int val);
Node *searchTree(Tree* tree,int val);
Node *maxNode(Tree *tree);
Node *minNode(Tree *tree);
Node *parentNode(Node *Node, Tree *tree);
Node *getNewNode(int val)
{
Node *p=(Node*)malloc(sizeof(Node));
p->val = val;
p->lchild = p->rchild = NULL;
return p;
}
Tree *getNewTree(void)
{
Tree *tree = (Tree*)malloc(sizeof(Tree));
tree->n = 0;
tree->root = NULL;
return tree;
}
void clearNode(Node *node)
{
if(node == NULL) return ;
clearNode(node->lchild);
clearNode(node->rchild);
free(node);
return ;
}//用递归去遍历并清除树
void clearTree(Tree*tree)
{
clearNode(tree->root);
free(tree);
return ;
}//
void outputNode(Node *root)
{
if(root == NULL) return ;
printf("%d",root->val);
if(root->lchild == NULL && root->rchild == NULL) return ;
printf("(");
outputNode(root->lchild);
printf(",");
outputNode(root->rchild);
printf(")");
return ;
}
void outputTree(Tree *tree)
{
printf("tree(%d)=",tree->n);
outputNode(tree->root);
return ;
}//转换为广义表
Node *insertNode(Node *root,int val,int* ret)
//二叉排序树,左子树小于根节点小于右节点,中序遍历!!!
{
if(root == NULL)
{
*ret = 1;
return getNewNode(val);//关键点!!!
}
if(root->val == val) return root;//什么都不干
if(root->val > val) root->lchild = insertNode(root->lchild,val,ret);//比当前根节点小插入左侧
else root->rchild = insertNode(root->rchild,val,ret);
return root;
}//用递归方法插入
int insert(Tree *tree,int val)
{
int flag = 0;
tree->root = insertNode(tree->root,val,&flag);
tree->n += flag;//flag为1插入成功,flag为0插入失败
return 1;
}
void preorderNode(Node *root)
{
if(root == NULL) return ;
printf("%d->",root->val);
preorderNode(root->lchild);
preorderNode(root->rchild);
return ;
}
void preorder(Tree *tree)
{
printf("preorder:");
preorderNode(tree->root);
printf("NULL");
printf("\n");
}
void inorderNode(Node *root)
{
if(root==NULL) return ;
inorderNode(root->lchild);
printf("%d->",root->val);
inorderNode(root->rchild);
}
void inorder(Tree *tree)
{
printf("inorder:");
inorderNode(tree->root);
printf("NULL");
printf("\n");
return ;
}
void postorderNode(Node *root)
{
if(root==NULL) return ;
postorderNode(root->lchild);
postorderNode(root->rchild);
printf("%d->",root->val);
}
void postorder(Tree *tree)
{
printf("postorder:");
postorderNode(tree->root);
printf("NULL");
printf("\n");
return ;
}
Node *searchNode1(Tree* tree,int val)
{
if(tree->root == NULL)
{
printf("The tree is empty!\n");
return NULL;
}
Node* p = tree->root;
while (p != NULL)
{
//找到了
if(val == p->val) return p;
else if(val < p->val) p = p->lchild;//在根的左子树
else p = p->rchild; //在根的右子树
}
printf("Not Found!\n");
return NULL;
} // 此处运用迭代进行遍历也可以用递归
Node *searchNode_Tree(Node* p,int val)
{
if(p == NULL) printf("Not Found!\n");
else if(val < p->val) return searchNode_Tree(p->lchild,val); //在根的左子树
else if(val > p->val) return searchNode_Tree(p->rchild,val); //在根的右子树
else return p;
return NULL;
}
Node *searchTree(Tree* tree,int val)
{
Node* p = tree->root;
if(p == NULL)
{
printf("The tree is empty!\n");
return NULL;
}
return searchNode_Tree(p,val);
}
Node *maxNode(Tree *tree)
{
if(tree->root == NULL) return NULL;
Node *p = tree->root;
while(p->rchild) p = p->rchild; //跳出循环后,p指向最后一个右子节点
return p;
}
Node *minNode(Tree *tree)
{
if(tree->root == NULL) return NULL;
Node *p = tree->root;
while(p->lchild) p = p->lchild; //跳出循环后,p指向最后一个右子节点
return p;
}
Node *parentNode(Node *Node, Tree *tree) //获取Node节点的父节点
{
Node *p = tree->root;
Node *parent = p;
if (Node == NULL || tree->root == NULL || tree->root == Node) return NULL;
while (p != NULL && p->val != Node->val)
{
parent = p;
if (Node->val > p->val) p = p->rchild; //每一次循环后parent总是p的父节点
else p = p->lchild;
}
if (p == NULL)
{
printf("节点Node不存在\n");
return NULL;
}
return parent;
}
int main(void)
{
srand(time(NULL));
Tree* tree = getNewTree();
for(int i=0; i<20; i++)
{
int val=rand()%100+1;
insert(tree,val);
outputTree(tree);
printf("\n");
}
printf("\n");
preorder(tree);
inorder(tree);
postorder(tree);
int val;
while(1)
{
scanf("%d",&val);
printf("%p\n",searchNode1(tree,val));
printf("%p\n",searchTree(tree,val));
}
return 0;
}