您的位置:首页 > 理论基础 > 数据结构算法

基本数据结构之二叉树

2015-07-13 19:47 537 查看

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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息