用C实现二叉树的遍历、存储

二叉树的知识点

在这里插入图片描述
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;
}


练习题

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值