数据结构——二叉树遍历及常见操作c代码实现

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

数据结构二叉树的常见遍历及其他常见操作。


1.头文件

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<assert.h>

//二叉树结构体
typedef struct treenode{
    int data;
    struct treenode *l, *r;
} TreeNode;


// 结点
typedef struct node{
    TreeNode* data;  //队列中元素类型为tree node
    struct node *next;
} Node;


//队列
typedef struct queue{
    int size;
    Node * front, *rear;   //队首结点(虚拟头结点)  队尾结点
} Queue;

//栈
typedef struct stack
{
    int size;
    Node * top, *head;  //栈顶结点   虚拟头结点  
} Stack;

//创建结点
Node *getNewNode(TreeNode* val);

//初始化栈
Stack* initStack();

//压栈
void pushStack(Stack *st, TreeNode *val);

//出栈
TreeNode* popStack(Stack *st);

//前序遍历(非递归实现)
void preorderTraversal(TreeNode * root);

//中序遍历(非递归实现)
void inorderTraversal(TreeNode * root);

//后序遍历(非递归实现)
void postorderTraversal(TreeNode * root);

//初始化队列
Queue* initQueue();

//元素入队
void pushQueue(Queue*que, TreeNode* node);

//元素出队
TreeNode* popQueue(Queue*que);

// 随机生成一颗二叉树
TreeNode* insertNodeToTree(TreeNode * root, int val);

//前序遍历(递归实现)
void preTraversal(TreeNode * root);

//中序遍历(递归实现)
void inTraversal(TreeNode * root);

//后序遍历(递归实现)
void postTraversal(TreeNode * root);

//层序遍历
void levelTraversal(TreeNode * root);

//获取树的高度
int getHeight(TreeNode * root);

//获取树中最大值
int getMaximum(TreeNode * root);

2.源代码

#include "binaryTree.h"


//创建结点
Node *getNewNode(TreeNode* val)
{
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = val;
    newNode->next = NULL;
    return newNode;
}

//初始化栈
Stack* initStack(){
    Stack * st = (Stack*)malloc(sizeof(Stack));
    TreeNode *tn = (TreeNode*)malloc(sizeof(TreeNode));
    tn->data = 0;
    st->head = getNewNode(tn);
    st->top = st->head;
    st->size = 0;
    return st;
}

//压栈
void pushStack(Stack *st, TreeNode *val){
    assert(st != NULL);
    Node * newnode = getNewNode(val);
    st->top->next = newnode;
    st->top = newnode;
    st->size++;
}


//出栈
TreeNode* popStack(Stack *st){
    assert(st != NULL);
    Node *p = st->head;
    while (p->next != st->top)
    {
        p = p->next;
    }
    Node* tmp = st->top;   //栈顶结点
    TreeNode *tn = tmp->data;  //得到结点的data,为树结点
    st->top = p;
    st->top->next = NULL;
    st->size--;
    free(tmp);
    return tn;
}


//前序遍历(非递归实现)
void preorderTraversal(TreeNode * root){
    assert(root != NULL);
    Stack *st = initStack();  //初始化栈
    pushStack(st, root);      //根结点入栈
    while (st->size != 0)     //当栈元素不为空时继续操作  
    {
        TreeNode * tmp = popStack(st);
        printf("%d ", tmp->data);
        if(tmp->r) pushStack(st, tmp->r);   //先进右子树  (栈为后进先出,先进后出) 
        if(tmp->l) pushStack(st, tmp->l);   //后进左子树  根左右
    }
}

//中序遍历(非递归实现)
void inorderTraversal(TreeNode * root){
    assert(root != NULL);
    Stack *st = initStack();  //初始化栈
    TreeNode *p = root;
    while (st->size != 0 || p)     //当栈元素不为空或者当前结点存在时  
    {   
        if(p){              //一直往左找到最左边的结点
            pushStack(st, p);
            p = p->l;
        }else{             //最左边的结点不存在则出栈当前元素,找右子树
            p = popStack(st);
            printf("%d ", p->data);
            p = p->r;
        }
    }

}

//后序遍历(非递归实现)
//只用对前序遍历的 左右子树  进行交换  变为 根进根出,左进右进右出左出(根右左) 反转得到左右根(直接使用栈进行反转)
void postorderTraversal(TreeNode * root){
    assert(root != NULL);
    Stack *st = initStack();  //初始化栈
    Stack *result = initStack(); //用来存储结果
    pushStack(st, root);
    while (st->size != 0)     //当栈元素不为空时继续操作  
    {   
        TreeNode * tmp = popStack(st);
        pushStack(result, tmp);
        if(tmp->l) pushStack(st, tmp->l);   
        if(tmp->r) pushStack(st, tmp->r);
    }
    for(int i = result->size; i > 0; i--){   //遍历栈 一次输出结果
        printf("%d ", popStack(result)->data);
    }
}

//初始化队列
Queue* initQueue(){
    Queue *que = (Queue*)malloc(sizeof(Queue));
    TreeNode *tn = (TreeNode*)malloc(sizeof(TreeNode));
    tn->data = 0;
    que->front = que->rear = getNewNode(tn);  //随机初始化一个值作为头尾结点  虚拟头
    que->size = 0;
    return que;
}

//元素入队
void pushQueue(Queue*que, TreeNode* node){
    assert(que != NULL);
    assert(node != NULL); 
    Node *newnode = getNewNode(node);  //新建一个结点
    que->rear->next = newnode;  //在尾结点后面追加新结点
    que->size++;  //尺寸+1
    que->rear = newnode; // 新加的结点变成了尾结点
}


//元素出队
TreeNode* popQueue(Queue*que){
    assert(que != NULL);
    // if(que->size == 0){                 
    //     return;         
    // }
    Node *tmp = que->front->next;  //让临时变量 保存真实第一个结点
    TreeNode * tn = tmp->data;
    que->front->next = tmp->next;
    if(tmp == que->rear){   //当队列只有一个元素时,让队尾重新回到队首
        que->rear = que->front;
    }
    que->size--;
    free(tmp);
    return tn;
}



// 随机生成一颗二叉树
TreeNode* insertNodeToTree(TreeNode * root, int val){    //传入根结点   还有要插入的数值
    TreeNode * tn = (TreeNode *)malloc(sizeof(TreeNode));   //新建一个新结点
    tn->data = val;    
    tn->l = NULL;
    tn->r = NULL;
    if(root == NULL){   //如果根结点为空  则把要插入的值放在根结点
        root = tn;
    }else{
        TreeNode *tmp = root;   //根结点不为空 开始向下寻找  定义临时结点变量
        while (tmp != NULL)   
        {
            if(val < tmp->data){     //如果要插入的值小于当前结点的值  放在左子树
                if(tmp->l == NULL){  //左子树为空 直接挂新结点 结束
                    tmp -> l = tn;
                    return root;
                }else{   //左子树不为空 把当前结点作为要遍历的结点继续向下寻找
                    tmp = tmp->l;
                }
            }else{                  //如果要插入的值大于当前结点的值  放在右子树
                if(tmp->r == NULL){ //右子树为空 直接挂新结点 结束
                    tmp -> r = tn;
                    return root;
                }else{   //右子树不为空 把当前结点作为要遍历的结点继续向下寻找
                    tmp = tmp->r;
                }
            }
        }
    }
    return root;
}


//前序遍历(递归实现)
void preTraversal(TreeNode * root){
    if(root == NULL) return;
    printf("%d ", root->data);  //根
    preTraversal(root->l) ;      //左
    preTraversal(root->r) ;      //右
}

//中序遍历(递归实现)
void inTraversal(TreeNode * root){
    if(root == NULL) return;
    inTraversal(root->l) ;       //左
    printf("%d ", root->data);  //根
    inTraversal(root->r) ;       //右
}

//后序遍历(递归实现)
void postTraversal(TreeNode * root){
    if(root == NULL) return;
    postTraversal(root->l) ;  //左
    postTraversal(root->r) ;  //右
    printf("%d ", root->data); //根
}

//层序遍历
void levelTraversal(TreeNode * root){
    assert(root != NULL);
    Queue*que = initQueue();
    pushQueue(que, root);  //根结点入队
    while (que->size > 0){
        TreeNode* tn = popQueue(que);  //获取出队树结点的值
        printf("%d ", tn->data);  //打印出队结点值
        if(tn->l)pushQueue(que, tn->l); //如果当前结点有左子树,左子树入队
        if(tn->r)pushQueue(que, tn->r); //如果当前结点有右子树,右子树入队
    }
}

//获取树的高度
int getHeight(TreeNode * root){
    if(root == NULL) return 0;
    else{
        int left_height = getHeight(root->l);   //得到左子树的高度
        int right_height = getHeight(root->r);  //得到右子树的高度
        int max = left_height;                 
        if(right_height > left_height){  //比较
            max = right_height;
        }
        return max + 1;   //+1 为根结点值
    }
}


//获取树中最大值
int getMaximum(TreeNode * root){
    if(root == NULL) return -1;
    else{
        int m1 = getMaximum(root->l);  //返回左子树的值
        int m2 = getMaximum(root->r);  //返回右子树的值
        int m3 = root->data;           //当前结点的值
        int max = m1;                  //初始最大值为左子树的值
        if(max < m2) max = m2;         //右子树大更新最大值为右子树值
        if(max < m3) max = m3;         //当前结点值大继续更新
        return max;
    }
}



int main(){
    system("chcp 65001"); /* cmd chcp 命令切换字符编码为 utf-8 以显示中文 */
    srand(time(NULL));  //设置随机种子 确保每次生成的数字是随机的
    int n, num[105] = {0};   //局部变量中必须手动初始化数组  不初始化会有脏数据
    TreeNode * root = (TreeNode*)malloc(sizeof(TreeNode));  //初始化一棵树
    root = NULL;
    scanf("%d", &n);
    for(int i = 0; i < n; i++){
        int x = rand() % 50;
        while (num[x] != 0)    //确保每次生成的数字不重复
        {
            x = rand() % 50;
        }
        num[x] = 1;
        root = insertNodeToTree(root, x);
    }
    printf("前序遍历(递归)  :");
    preTraversal(root);  

    printf("\n中序遍历(递归)  :");
    inTraversal(root);

    printf("\n后序遍历(递归)  :");
    postTraversal(root);

    printf("\n前序遍历(非递归):");
    preorderTraversal(root);  

    printf("\n中序遍历(非递归):");
    inorderTraversal(root); 

    printf("\n后序遍历(非递归):");
    postorderTraversal(root);

    printf("\n层序遍历:");
    levelTraversal(root);

    int height = getHeight(root);
    printf("\n树高为: %d", height);

    int maxnum = getMaximum(root);
    printf("\n最大值为: %d", maxnum);

    return 0;
}

3.提示

转载请注明出处

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值