二叉树的知识点
1.节点的度:当前节点下面挂了几个子节点,就是多少度
2.节点的深度:从根节点往下看,当前节点位于第几层
3.节点的高度:从整个数的最后一层往上看,当前节点比最后一层高几层
节点是在前还是中还是后来看
完全二叉树,只有树的最右边的右子位可以缺少一个,其它地方都不能缺
排序二叉树
/**********************************************************
这是一个排序二叉树,也叫查找二叉树,左子树的小于中间节点,中间节点小于右子树
可以将存储的数据由小到大打印输出
也可以由大到小打印输出
还可以将二叉树转化为广义表输出
*******************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef struct Node
{
int data;
struct Node *lchild, *rchild;
}Node;
typedef struct Tree
{
Node *root;
int n;
}Tree;
Tree *GetNewTree()
{
Tree *p = (Tree *)malloc(sizeof(Tree));
p->root = NULL;
p->n = 0;
return p;
}
Node *GetNewNode(int val)
{
Node *p = (Node *)malloc(sizeof(Node));
p->data = val;
p->lchild = p->rchild = NULL;
return p;
}
Node* insert_binary_node(Node *node,int val,int *flag) //
{
if(node == NULL){
node = GetNewNode(val);
*flag = 1; //用来判断插入是否成功
return node;
}
if(node->data == val)
return node;
else if(node ->data>val){
node->lchild=insert_binary_node(node->lchild, val,flag);
}
else {
node->rchild=insert_binary_node(node->rchild, val,flag);
}
return node;
}
void insert_binary(Tree *tree,int val)
{
if(tree == NULL) return ;
int flag = 0;
tree->root = insert_binary_node(tree->root, val,&flag);
tree->n += flag; //通过flag来计数节点的个数
return;
}
void Pre_Out_Node(Node *node) //这里的前序遍历也是一种迭代的形式,也满足入栈出栈的一种思想
{
if(node == NULL)
return;
printf("%d ", node->data);
Pre_Out_Node(node->lchild);
Pre_Out_Node(node->rchild);
return;
}
void Pre_Out(Tree* tree)
{
if(tree ==NULL)
return;
printf("Pre_Out: ");
Pre_Out_Node(tree->root);
printf("\n");
return;
}
void in_Out_Node(Node *node) //这里的中序遍历可以将二叉树里的数据按从小到大输出
{
if(node == NULL)
return;
in_Out_Node(node->lchild);
printf("%d ", node->data);
in_Out_Node(node->rchild);
return;
}
void in_Out(Tree* tree)
{
if(tree ==NULL)
return;
printf("in_Out: ");
in_Out_Node(tree->root);
printf("\n");
return;
}
void rin_Out_Node(Node *node) //这里的中序遍历改版可以将二叉树里的数据按从大到小输出
{
if(node == NULL)
return;
rin_Out_Node(node->rchild);
printf("%d ", node->data);
rin_Out_Node(node->lchild);
return;
}
void rin_Out(Tree* tree)
{
if(tree ==NULL)
return;
printf("in_Out: ");
rin_Out_Node(tree->root);
printf("\n");
return;
}
void post_Out_Node(Node *node) //这里的后序遍历
{
if(node == NULL)
return;
post_Out_Node(node->lchild);
post_Out_Node(node->rchild);
printf("%d ", node->data);
return;
}
void post_Out(Tree* tree)
{
if(tree ==NULL)
return;
printf("post_Out: ");
post_Out_Node(tree->root);
printf("\n");
return;
}
void Clear_Node(Node *node)
{
if (node == NULL)
return;
// Clear_Node(node->lchild);
// free(node);
// Clear_Node(node->rchild);
// free(node);
/*不能以上面那种方式进行删除,上面的子节点没有释放完毕就开始释放当前节点会造成内存泄露
下面这种左边和右边都迭代到底然后在释放迭代到底的那个节点,这样可以保证释放的节点都是当前最底部的
不会造成内存泄露*/
Clear_Node(node->lchild);
Clear_Node(node->rchild);
free(node);
}
void Clear_Tree(Tree *tree)
{
if(tree == NULL)
return;
Clear_Node(tree->root);
free(tree);
}
void OutNode_bin_table(Node *root)
{
if(root == NULL)
return;
printf("%d ", root->data);
if(root->lchild == NULL && root->rchild == NULL)
return;
printf("(");
OutNode_bin_table(root->lchild);
printf(",");
OutNode_bin_table(root->rchild);
printf(")");
return;
}
void Out_bin_table(Tree *tree)
{
if(tree == NULL)
return;
printf("tree(%d) :", tree->n);
OutNode_bin_table(tree->root);
printf("\n");
return;
}
int main(int argc, char const *argv[])
{
srand(time(0));
Tree *tree = GetNewTree();
#define max_op 10
for (int i = 0; i < max_op; i++)
{
int val = rand() % 100;
insert_binary(tree, val);
Out_bin_table(tree);
}
Pre_Out(tree);
in_Out(tree);
rin_Out(tree);
#undef max_op
Clear_Tree(tree);
return 0;
}
广义表转二叉树
/***********************************
广义表转二叉树
需要栈来匹配根节点和左右子节点,用了栈的递归思想,先找到最内层最里面的子节点然后在往外扩
用二叉树来存储节点数据
这里只能转换用字符表示的广义表用数字的还不行
***********************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include<string.h>
typedef struct Node
{
int data;
struct Node *lchild, *rchild;
}Node;
typedef struct Tree
{
Node *root;
int n;
}Tree;
typedef struct Stack {
Node **data; //指向堆中数组的指针,但是因为这里的数组是存储地址的所有是两个*
int size, top; //size是数组的大小,top为数组中存储的最新数据的下标
} Stack;
Tree *GetNewTree()
{
Tree *p = (Tree *)malloc(sizeof(Tree));
p->root = NULL;
p->n = 0;
return p;
}
Node *GetNewNode(int val)
{
Node *p = (Node *)malloc(sizeof(Node));
p->data = val;
p->lchild = p->rchild = NULL;
return p;
}
Stack *init(int n) {
Stack *s = (Stack *)malloc(sizeof(Stack));
s->data = (Node **)malloc(sizeof(Node *) * n);
s->size = n;
s->top = -1;
return s;
}
Node* top(Stack *s) { //访问数组中top下标所在的数据,就是栈顶的最新数据
return s->data[s->top];
}
int empty(Stack *s) {
return s->top == -1;
}
int push(Stack *s, Node* val) {
if (s == NULL) return 0;
if (s->top == s->size - 1) return 0; //
s->data[++(s->top)] = val;
return 1;
}
int pop(Stack *s) {
if (s == NULL) return 0;
if (empty(s)) return 0;
s->top -= 1;
return 1;
}
void clear(Stack *s) {
if (s == NULL) return ;
free(s->data);
free(s);
return ;
}
void Clear_Node(Node *node)
{
if (node == NULL)
return;
// Clear_Node(node->lchild);
// free(node);
// Clear_Node(node->rchild);
// free(node);
/*不能以上面那种方式进行删除,上面的子节点没有释放完毕就开始释放当前节点会造成内存泄露
下面这种左边和右边都迭代到底然后在释放迭代到底的那个节点,这样可以保证释放的节点都是当前最底部的
不会造成内存泄露*/
Clear_Node(node->lchild);
Clear_Node(node->rchild);
free(node);
}
void Clear_Tree(Tree *tree)
{
if(tree == NULL)
return;
Clear_Node(tree->root);
free(tree);
}
Node* build(const char *str,int *node_num)
{
Stack *s = init(strlen(str));
Node *temp = NULL, *p = NULL;
int flag = 0;
while (str[0])
{
switch (str[0])
{
case '(':
push(s, temp);
flag = 0;
break;
case ')':
p = top(s);
pop(s);
break;
case ',':
flag = 1;
break;
case ' ':
break;
default:
{
temp = GetNewNode(str[0]);
if (!empty(s) && flag == 0)
{
top(s)->lchild = temp;
}else if (!empty(s) && flag == 1)
{
top(s)->rchild = temp;
}
++(*node_num);
}
break;
}
++str;
}
clear(s); //出现A只有一个根节点的情况
if (temp && !p)
p = temp;
return p;
}
void Pre_Out_Node(Node *node) //这里的前序遍历也是一种迭代的形式,也满足入栈出栈的一种思想
{
if(node == NULL)
return;
printf("%c ", node->data);
Pre_Out_Node(node->lchild);
Pre_Out_Node(node->rchild);
return;
}
void Pre_Out(Tree* tree)
{
if(tree ==NULL)
return;
printf("Pre_Out: ");
Pre_Out_Node(tree->root);
printf("\n");
return;
}
void in_Out_Node(Node *node) //这里的中序遍历可以将二叉树里的数据按从小到大输出
{
if(node == NULL)
return;
in_Out_Node(node->lchild);
printf("%c ", node->data);
in_Out_Node(node->rchild);
return;
}
void in_Out(Tree* tree)
{
if(tree ==NULL)
return;
printf("in_Out: ");
in_Out_Node(tree->root);
printf("\n");
return;
}
void rin_Out_Node(Node *node) //这里的中序遍历改版可以将二叉树里的数据按从大到小输出
{
if(node == NULL)
return;
rin_Out_Node(node->rchild);
printf("%d ", node->data);
rin_Out_Node(node->lchild);
return;
}
void rin_Out(Tree* tree)
{
if(tree ==NULL)
return;
printf("in_Out: ");
rin_Out_Node(tree->root);
printf("\n");
return;
}
void post_Out_Node(Node *node) //这里的后序遍历
{
if(node == NULL)
return;
post_Out_Node(node->lchild);
post_Out_Node(node->rchild);
printf("%c ", node->data);
return;
}
void post_Out(Tree* tree)
{
if(tree ==NULL)
return;
printf("post_Out: ");
post_Out_Node(tree->root);
printf("\n");
return;
}
int main(int argc, char const *argv[])
{
char str[1000] = {0};
int node_num = 0;
scanf("%[^\n]s", str);
printf("%s\n", str);
for (int i = 0; i < 10; i++)
{
printf("%c\n", str[i]);
}
Tree *tree = GetNewTree();
tree->root = build(str, &node_num);
tree->n = node_num;
Pre_Out(tree);
in_Out(tree);
post_Out(tree);
Clear_Tree(tree);
return 0;
}