基本数据结构之二叉树

C语言实现二叉树的遍历

二叉树结点的定义

/*
    先序,中序,后序的遍历时间复杂度为O(n),每个结点只访问一次。

    层序的时间复杂度最差为O(n^2),当二叉树基本平衡时,时间复杂度为O(n)

    n为结点个数
*/

typedef int tree_node_element;
/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的结点数据结构
 *  
 */
typedef struct binary_tree_node
{
    binary_tree_node* left; //左孩子
    binary_tree_node* right; //右孩子
    tree_node_element element; //数据节点

    //构造函数
    binary_tree_node(tree_node_element x) : element(x), left(NULL), right(NULL) {}
}binary_tree_node;

二叉树递归遍历

/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的前序遍历,递归 根-左-右
 * @param root根节点
 * @param visit 访问根节点的函数指针
 * @return 无返回
 *  
 */
void pre_order_r(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    if (root == NULL)
        return;
    visit(root);
    pre_order_r(root->left, visit);
    pre_order_r(root->right, visit);
}

/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的中序遍历 ,递归版 左-根-右
 * @param root根节点
 * @param visit 访问根节点的函数指针
 * @return 无
 *  
 */
void in_order_r(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    if (root == NULL)
        return;
    in_order_r(root->left, visit);
    visit(root);
    in_order_r(root->right, visit);
}
/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的后序遍历 ,递归版 左-右-根
 * @param root根节点
 * @param visit 访问根节点的函数指针
 * @return 无
 *  
 */
void post_order_r(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    if (root == NULL)
        return;
    post_order_r(root->left, visit);
    post_order_r(root->right, visit);
    visit(root);
}

二叉树的非递归遍历


/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的前序遍历,非递归版 -- 使用栈完成,递归的本质也是栈
 * @param root根节点
 * @param visit 访问根节点的函数指针
 * @return
 *  
 */
void pre_order(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    const binary_tree_node *temp = root;
    std::stack<const binary_tree_node*> avgSatck;

    //首先根节点入栈
    if (temp != NULL)
        avgSatck.push(temp);
    while (!avgSatck.empty())
    {
        temp = avgSatck.top(); //在这里改变temp
        avgSatck.pop(); 
        visit(temp); //第一步打印出根节点之后,栈是空的。

        if (temp->right != NULL)
            avgSatck.push(temp->right);

        if (temp->left != NULL)
            avgSatck.push(temp->left);
    }
}

/**
* @author 韦轩
* @time 2015/07/11
* @brief 二叉树的中序遍历,非递归版 -- 使用栈完成,递归的本质也是栈
* @param root根节点
* @param visit 访问根节点的函数指针
* @return
*
*/
void in_order(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    const binary_tree_node *temp;
    std::stack<const binary_tree_node*> avgSatck;
    temp = root;
    while (!avgSatck.empty() || temp != NULL)
    {
        if (temp != NULL)
        {
            avgSatck.push(temp);
            temp = temp->left;
        }
        else
        {
            temp = avgSatck.top();
            avgSatck.pop();
            visit(temp);
            temp = temp->right;
        }
    }
}

/**
* @author 韦轩
* @time 2015/07/11
* @brief 二叉树的后序遍历,非递归版 -- 使用栈完成,递归的本质也是栈
* @param root根节点
* @param visit 访问根节点的函数指针
* @return
*
*/
void post_order(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    const binary_tree_node *temp1,*temp2;
    std::stack<const binary_tree_node*> avgSatck;
    temp1 = root;

    do 
    {
        while (temp1 != NULL)
        {
            avgSatck.push(temp1);
            temp1 = temp1->left;
        }
        temp2 = NULL;
        while (!avgSatck.empty())
        {
            temp1 = avgSatck.top();
            avgSatck.pop();

            if (temp1->right == temp2)
            {
                visit(temp1);
                temp2 = temp1;
            }
            else
            {
                avgSatck.push(temp1);
                temp1 = temp1->right;
                break;
            }
        }
    } while (!avgSatck.empty());
}
二叉树的层次遍历
层次遍历个非递归的前序遍历代码一样,只不过要将辅助的存储结构改为队列
/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的层次遍历 和前序遍历一模一样,不过改用队列存储
 * @param root根节点
 * @param visit 访问根节点的函数指针
 * @return
 *  
 */
void level_order(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    const binary_tree_node *temp = root;
    std::queue<const binary_tree_node*> avgQueue;

    if (temp != NULL)
        avgQueue.push(temp);
    while (!avgQueue.empty())
    {
        temp = avgQueue.front();
        avgQueue.pop();
        visit(temp);

        if (temp->left != NULL)
            avgQueue.push(temp->left);
        if (temp->right != NULL)
            avgQueue.push(temp->right);
    }
}

完整的工程

#include <iostream>
#include <stack>
#include <queue>
#include <math.h>

/*
    先序,中序,后序的遍历时间复杂度为O(n),每个结点只访问一次。

    层序的时间复杂度最差为O(n^2),当二叉树基本平衡时,时间复杂度为O(n)

    n为结点个数
*/

typedef int tree_node_element;
/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的结点数据结构
 *  
 */
typedef struct binary_tree_node
{
    binary_tree_node* left; //左孩子
    binary_tree_node* right; //右孩子
    tree_node_element element; //数据节点

    //构造函数
    binary_tree_node(tree_node_element x) : element(x), left(NULL), right(NULL) {}
}binary_tree_node;

/* 二叉树的遍历,包括递归和非递归版本 */

/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的前序遍历,递归 根-左-右
 * @param root根节点
 * @param visit 访问根节点的函数指针
 * @return 无返回
 *  
 */
void pre_order_r(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    if (root == NULL)
        return;
    visit(root);
    pre_order_r(root->left, visit);
    pre_order_r(root->right, visit);
}

/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的中序遍历 ,递归版 左-根-右
 * @param root根节点
 * @param visit 访问根节点的函数指针
 * @return 无
 *  
 */
void in_order_r(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    if (root == NULL)
        return;
    in_order_r(root->left, visit);
    visit(root);
    in_order_r(root->right, visit);
}
/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的后序遍历 ,递归版 左-右-根
 * @param root根节点
 * @param visit 访问根节点的函数指针
 * @return 无
 *  
 */
void post_order_r(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    if (root == NULL)
        return;
    post_order_r(root->left, visit);
    post_order_r(root->right, visit);
    visit(root);
}

/*二叉树遍历的非递归版*/

/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的前序遍历,非递归版 -- 使用栈完成,递归的本质也是栈
 * @param root根节点
 * @param visit 访问根节点的函数指针
 * @return
 *  
 */
void pre_order(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    const binary_tree_node *temp = root;
    std::stack<const binary_tree_node*> avgSatck;

    //首先根节点入栈
    if (temp != NULL)
        avgSatck.push(temp);
    while (!avgSatck.empty())
    {
        temp = avgSatck.top(); //在这里改变temp
        avgSatck.pop(); 
        visit(temp); //第一步打印出根节点之后,栈是空的。

        if (temp->right != NULL)
            avgSatck.push(temp->right);

        if (temp->left != NULL)
            avgSatck.push(temp->left);
    }
}

/**
* @author 韦轩
* @time 2015/07/11
* @brief 二叉树的中序遍历,非递归版 -- 使用栈完成,递归的本质也是栈
* @param root根节点
* @param visit 访问根节点的函数指针
* @return
*
*/
void in_order(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    const binary_tree_node *temp;
    std::stack<const binary_tree_node*> avgSatck;
    temp = root;
    while (!avgSatck.empty() || temp != NULL)
    {
        if (temp != NULL)
        {
            avgSatck.push(temp);
            temp = temp->left;
        }
        else
        {
            temp = avgSatck.top();
            avgSatck.pop();
            visit(temp);
            temp = temp->right;
        }
    }
}

/**
* @author 韦轩
* @time 2015/07/11
* @brief 二叉树的后序遍历,非递归版 -- 使用栈完成,递归的本质也是栈
* @param root根节点
* @param visit 访问根节点的函数指针
* @return
*
*/
void post_order(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    const binary_tree_node *temp1,*temp2;
    std::stack<const binary_tree_node*> avgSatck;
    temp1 = root;

    do 
    {
        while (temp1 != NULL)
        {
            avgSatck.push(temp1);
            temp1 = temp1->left;
        }
        temp2 = NULL;
        while (!avgSatck.empty())
        {
            temp1 = avgSatck.top();
            avgSatck.pop();

            if (temp1->right == temp2)
            {
                visit(temp1);
                temp2 = temp1;
            }
            else
            {
                avgSatck.push(temp1);
                temp1 = temp1->right;
                break;
            }
        }
    } while (!avgSatck.empty());
}

/**
 * @author 韦轩
 * @time 2015/07/11
 * @brief 二叉树的层次遍历 和前序遍历一模一样,不过改用队列存储
 * @param root根节点
 * @param visit 访问根节点的函数指针
 * @return
 *  
 */
void level_order(const binary_tree_node *root, int(*visit)(const binary_tree_node*))
{
    const binary_tree_node *temp = root;
    std::queue<const binary_tree_node*> avgQueue;

    if (temp != NULL)
        avgQueue.push(temp);
    while (!avgQueue.empty())
    {
        temp = avgQueue.front();
        avgQueue.pop();
        visit(temp);

        if (temp->left != NULL)
            avgQueue.push(temp->left);
        if (temp->right != NULL)
            avgQueue.push(temp->right);
    }
}

/**
 * @author 韦轩
 * @time 2015/07/12
 * @brief 实现二叉树的高度
 * @param 
 * @return 高度
 *  
 */
int getHeight(const binary_tree_node *root)
{
    if (root == NULL)
        return 0;
    return getHeight(root->left)>getHeight(root->right) ? getHeight(root->left) : getHeight(root->right) + 1;
}
/**
 * @author 韦轩
 * @time 2015/07/12
 * @brief  visit 函数
 *  
 */
int visit(const binary_tree_node* node)
{
    if (node != NULL)
    {
        printf_s("%d ", node->element);
        return node->element;
    }
}

int  main()
{
    binary_tree_node root(1);
    binary_tree_node n1(2);
    binary_tree_node n2(3);
    binary_tree_node n3(4);
    binary_tree_node n4(5);
    binary_tree_node n5(6);
    binary_tree_node n6(7);

    binary_tree_node* proot = &root;
    binary_tree_node* pn1 = &n1;
    binary_tree_node* pn2 = &n2;
    binary_tree_node* pn3 = &n3;
    binary_tree_node* pn4 = &n4;
    binary_tree_node* pn5 = &n5;
    binary_tree_node* pn6 = &n6;

    proot->left = pn1;
    proot->right = pn2;

    pn1->left = pn3;
    pn1->right = pn4;

    pn2->left = pn5;
    pn2->right = pn6;

    pn3->left = NULL;
    pn3->right = NULL;

    pn4->left = NULL;
    pn4->right = NULL;

    pn5->left = NULL;
    pn5->right = NULL;

    pn6->left = NULL;
    pn6->right = NULL;


    pre_order_r(proot, visit);
    puts("\n");
    pre_order(proot, visit);
    puts("\n");
    in_order_r(proot, visit);
    puts("\n");
    in_order(proot, visit);
    puts("\n");

    post_order_r(proot, visit);
    puts("\n");

    post_order(proot, visit);
    puts("\n");

    level_order(proot,visit);
    puts("\n");

    int h = getHeight(proot);

    return 0;
}

二叉树的特点

三种遍历算法中,基本的结点都只访问一次,时间复杂度是O(n),同时,空间复杂度也是O(n)
层次遍历的时间复杂度和二叉树的平衡有关,极端情况下,时间复杂度是O(N^2),平衡二叉树的时间复杂度是O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值