基本数据结构之二叉树

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)

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 16:29:57

基本数据结构之二叉树的相关文章

数据结构:二叉树的链式存储

数据结构:二叉树的链式存储(C语言版) 1.写在前面 二叉树同样有两种存储方式,数组和链式存储,对于数组来说,我们利用二叉树的性质然后利用下标可以方便的找到一个节点的子节点和父节点. 二叉树的性质: 1.二叉树的第i层上至多有2i-1个节点 2.深度为K的二叉树至多有2k-1个节点 3.任何一个二叉树中度数为2的节点的个数必度数为0的节点数目少1. 说明:度数为0,为叶子节点. 4.具有n个节点的完全二叉树的深度为|_Log2N_|+1 5.若完全二叉树中的某节点编号为i,则若有左孩子编号为2i

数据结构之二叉树查找

数据结构之--二叉树查找 定义:它是一棵树,或者具有以下性质的树.  若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值:  它的左.右子树也分别为二叉排序树: 图解: ?        ?    ?    ?    ?    ?? #include<stdio.h> #include<stdlib.h> typedef int Status; #define TRUE 1 #define FALSE 0 t

数据结构之二叉树遍历

二叉树的 二叉树节点的描述 public class BiTNode { char data; BiTNode lc,rc; } 下面我们分别用递归和非递归实现前.中.后序遍历,以及使用了两种方法来进行层次遍历二叉树,一种方法就是使用STL中的queue,另外一种方法就是定义了一个数组队列,分别使用了front和rear两个数组的下标来表示入队与出队. 1.前序遍历 未完待续... 数据结构之二叉树遍历,布布扣,bubuko.com

【算法与数据结构】二叉树 中序线索

中序线索二叉树 /************************************************************************ 线索二叉树 二叉树的节点有五部分构造 ----------------------------------------- | lChild | lTag | value | rTag | rChild | ----------------------------------------- lChild = (lTag == 0 ? 左

【算法与数据结构】二叉树的 中序 遍历

前一篇写了二叉树的先序遍历,本篇记录一下二叉树的中序遍历,主要是非递归形式的中序遍历. 由于距离上篇有好几天了,所以这里把二叉树的创建和存储结构也重复的写了一遍. 二叉树如下 二叉树的存储方式依然是二叉链表方式,其结构如下 typedef struct _tagBinTree { unsigned char value; struct _tagBinTree* left; struct _tagBinTree* right; }BinTree, *PBinTree; 先序递归形式的创建二叉树代码

数据结构之二叉树的遍历汇总

声明:小弟写博客不久,主要是边上班边学习边写博客,如果错误,望各位包涵并指导. 二叉树是一种常用的非线性数据结构,二叉树是由一个根节点和称为根的左.右子树的两颗互不相交的二叉树构成.二叉树具有一些特殊的性质,如第i层上最多有2^(i-1)个结点.二叉树的链式存储结构如下: typedef struct BTNode { char data; //字符型数据; struct BTNode* lChild,*rChild; //左右子结点的指针; }BTNode,*BiTree; data为二叉树中

采用栈数据结构的二叉树遍历

[前言]树的遍历,根据访问自身和其子节点之间的顺序关系,分为前序,后序遍历.对于二叉树,每个节点至多有两个子节点(特别的称为左,右子节点),又有中序遍历.由于树自身具有的递归性,这些遍历函数使用递归函数很容易实现,代码也非常简洁.借助于数据结构中的栈,可以把树遍历的递归函数改写为非递归函数. 在这里我思考的问题是,很显然,循环可以改写为递归函数.递归函数是否借助栈这种数据结构改写为循环呢.因为函数调用中,call procedure stack 中存储了流程的 context,调用和返回相当于根

python环境下使用mysql数据及数据结构和二叉树算法(图)

python环境下使用mysql数据及数据结构和二叉树算法(图):1 python环境下使用mysql2使用的是 pymysql库3 开始-->创建connection-->获取cursor-->操作-->关闭cursor->关闭connection->结束45 代码框架6 import pymysql.cursors7 ###连接数据库8 connection = pymysql.connect(host='127.0.0.1',port=3306,user='roo

数据结构-二叉树笔记

看完<数据结构与算法分析>(c描述)后对二叉树的一点总结 树的节点声明: 1 typedef int ElementType; 2 typedef struct TreeNode* Position; 3 typedef Position BiSearchTree; 4 5 struct TreeNode 6 { 7 ElementType Element; 8 Position Left,Right; 9 10 }; 二叉查找树的定义如下: 1.二叉查找树首先是一棵二叉树: 2.二叉查找树除