2019-04-30 17:11:12
重新拿c++实现了一下
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
class tree_node
{
public:
int data;
tree_node *lchild;
tree_node *rchild;
~tree_node(){
lchild = nullptr;
rchild = nullptr;
}
};
class binary_tree
{
public:
tree_node *build_tree(int level, string pos);
void pre_order(tree_node *root);
void in_order(tree_node *root);
void post_order(tree_node *root);
int sum_node(tree_node *root);
int sum_leaf(tree_node *root);
bool tree_equals(tree_node *root1, tree_node *root2);
void destory_tree(tree_node *root);
tree_node *copy_tree(tree_node *root);
void non_rec_pre_order(tree_node *root);
void non_rec_in_order(tree_node *root);
void non_rec_post_order(tree_node *root);
void level_order(tree_node *root);
void invert_level_order(tree_node *root);
int tree_depth(tree_node *root);
int tree_depth2(tree_node *root);
void find_x_level(tree_node *root, int x);
tree_node *pre_in_create_tree2(int A[], int B[], int s1, int e1, int s2, int e2);
tree_node *pre_in_create_tree(int A[],int B[], int s1, int e1, int s2, int e2);
bool is_complete(tree_node *root);
int double_son_node(tree_node *root);
void swap_lrchild(tree_node *root);
void swap_lrchild2(tree_node *root);
int search_k_node(tree_node *root, int k);
void destory_x_node(tree_node *root, int k);
void print_ancestor_node(tree_node *root, int x);
tree_node *nearest_comm_ancestor(tree_node *root, int p, int q);
int tree_width(tree_node *root);
void pre_to_post(int pre[], int s1, int e1,
int post[], int s2, int e2);
tree_node *inorder_list(tree_node *root);
void link(tree_node *root, tree_node *head, tree_node *tail);
bool is_similar(tree_node *root1, tree_node *root2);
int WPL(tree_node *node);
~binary_tree(){
root = nullptr;
}
tree_node *root;
};
tree_node *binary_tree::build_tree(int level, string pos) {
int tmp;
cin >> tmp;
if(tmp == 0)
return nullptr;
tree_node *p_new = new tree_node();
p_new->data = tmp;
p_new->lchild = build_tree(level+1, "left");
p_new->rchild = build_tree(level+1, "right");
return p_new;
}
void binary_tree::pre_order(tree_node *root) {
if(root)
{
cout << root->data << endl;
pre_order(root->lchild);
pre_order(root->rchild);
}
}
void binary_tree::in_order(tree_node *root) {
if(root)
{
in_order(root->lchild);
cout << root->data << endl;
in_order(root->rchild);
}
}
void binary_tree::post_order(tree_node *root) {
if(root)
{
post_order(root->lchild);
post_order(root->rchild);
cout << root->data << endl;
}
}
int binary_tree::sum_node(tree_node *root) {
if(root == nullptr)
return 0;
else{
return sum_node(root->lchild) + sum_node(root->rchild) + 1;
}
return 0;
}
// 统计叶子节点的个数
int binary_tree::sum_leaf(tree_node *root) {
int sum=0;
if(root)
{
if(root->lchild==nullptr && root->rchild==nullptr)
sum++;
if(root->lchild)
sum += sum_leaf(root->lchild);
if(root->rchild)
sum += sum_leaf(root->rchild);
}
return sum;
}
bool binary_tree::tree_equals(tree_node *root1, tree_node *root2) {
if(root1 == nullptr && root2 == nullptr)
return true;
if(root1 && root2 && root1->data == root2->data)
if(tree_equals(root1->lchild,root2->lchild))
if(tree_equals(root1->rchild, root2->rchild))
return true;
return false;
}
/// delete 会调用析够函数,对对象进行释放
/// 这个代码不能有效删除树根节点 root
void binary_tree::destory_tree(tree_node *root) {
if(root == nullptr)
return;
destory_tree(root->lchild);
destory_tree(root->rchild);
delete root;
root = nullptr;
return;
}
tree_node *get_tree_node(int data, tree_node *lchild, tree_node *rchild)
{
tree_node *p_tmp = new tree_node();
p_tmp->data = data;
p_tmp->lchild = lchild;
p_tmp->rchild = rchild;
return p_tmp;
}
tree_node *binary_tree::copy_tree(tree_node *root) {
tree_node *new_l, *new_r, *new_root;
if(root == nullptr)
return nullptr;
if(root->lchild)
new_l = copy_tree(root->lchild);
else
new_l = nullptr;
if(root->rchild)
new_r = copy_tree(root->rchild);
else
new_r = nullptr;
new_root = get_tree_node(root->data, new_l, new_r);
return new_root;
}
void binary_tree::non_rec_pre_order(tree_node *root) {
/**
类名后面加*,表示该类型为对应类的指针类型。
指针类型为C/C++语言的特色概念,其值为对象的地址。
类名加*,有两种作用情况:
1 用于定义时,或用于函数参数,返回值时,表示对应变量值为类指针类型;
2 用于变量前,以(CLASS_NAME *)var_name,形式出现时,表示将变量或常量var_name强制转换为类指针类型。
* */
stack<tree_node *> tree_stack;
if(root == nullptr)
return;
else{
while(root || !tree_stack.empty())
{
if(root)
{
cout << root->data << endl;
tree_stack.push(root);
root = root->lchild;
}else{
root = tree_stack.top();
tree_stack.pop();
root = root->rchild;
}
}
}
}
void binary_tree::non_rec_in_order(tree_node *root) {
stack<tree_node *> tree_stack;
if(root==nullptr)
return;
else{
while(root || !tree_stack.empty())
{
if(root){
tree_stack.push(root);
root=root->lchild;
}else{
root=tree_stack.top();
tree_stack.pop();
cout << root->data << endl;
root=root->rchild;
}
}
}
}
void binary_tree::non_rec_post_order(tree_node *root) {
stack<tree_node *> tree_stack;
tree_node *vis = nullptr;
if(root == nullptr)
return;
while(root || !tree_stack.empty())
{
if(root)
{
tree_stack.push(root);
root = root->lchild;
}else{
root = tree_stack.top();
if(root->rchild && root->rchild != vis)
{
root=root->rchild;
tree_stack.push(root);
root=root->lchild;
}else{
root=tree_stack.top();
tree_stack.pop();
cout << root->data << endl;
vis=root;
root=nullptr;
}
}
}
}
/**
* 学会使用stl后,代码超级简单,还不用记忆各个容器的具体操作
* */
void binary_tree::level_order(tree_node *root) {
queue<tree_node *> tree_que;
if(root == nullptr)
return;
tree_que.push(root);
while(!tree_que.empty())
{
root = tree_que.front();
tree_que.pop();
cout << root->data<< endl;
if(root->lchild)
tree_que.push(root->lchild);
if (root->rchild)
tree_que.push(root->rchild);
}
}
/**
* 逆层次遍历
*
* */
void binary_tree::invert_level_order(tree_node *root) {
queue<tree_node *> tree_que;
stack<tree_node *> tree_stack;
if(root == nullptr)
return;
tree_que.push(root);
while(!tree_que.empty())
{
root = tree_que.front();
tree_que.pop();
tree_stack.push(root);
if(root->lchild)
tree_que.push(root->lchild);
if(root->rchild)
tree_que.push(root->rchild);
}
while(!tree_stack.empty())
{
root = tree_stack.top();
tree_stack.pop();
cout << root->data << endl;
}
}
/**
*
1.每遍历一层,depth++;
2.每一层,需使用一个变量len记录该层的结点个数,也就是队列的当前长度,
然后依次在队列中访问该层的len个结点(将队列中len个元素出队列),
并将下一层如队列
* */
int binary_tree::tree_depth(tree_node *root) {
queue<tree_node *> tree_que;
if(root == nullptr)
return 0;
int level=0;
tree_que.push(root);
while(!tree_que.empty())
{
unsigned long tree_size=tree_que.size();
level++;
while(tree_size--)
{
tree_node *tmp = tree_que.front();
tree_que.pop();
if(tmp->lchild)
tree_que.push(tmp->lchild);
if(tmp->rchild)
tree_que.push(tmp->rchild);
}
}
return level;
}
int binary_tree::tree_depth2(tree_node *root) {
int level=0;
if(!root)
return 0;
else
{
level = 1 + max(tree_depth2(root->lchild), tree_depth2(root->rchild));
}
return level;
}
void binary_tree::find_x_level(tree_node *root, int x) {
static int level=1;
if(root)
{
if(root->data == x)
{
cout << level << endl;
return;
}
level++;
find_x_level(root->lchild, x);
find_x_level(root->rchild, x);
}
}
tree_node *binary_tree::pre_in_create_tree2(int *A, int *B, int s1, int e1, int s2, int e2) {
if(s1>e1 || s2>e2)
return nullptr;
tree_node *root = new tree_node();
root->data=A[s1];
for(int i=s2; i<=e2; ++i)
{
if(A[s1] == B[i])
{
root->lchild=pre_in_create_tree2(A,B,s1+1,s1+i-s2, s2, i-1);
root->rchild=pre_in_create_tree2(A,B,i-s2+s1+1,e1,i+1,e2);
}
}
return root;
}
tree_node *binary_tree::pre_in_create_tree(int *A, int *B, int s1, int e1, int s2, int e2) {
return nullptr;
}
/**
* 对应于博客上的代码是有问题的,617行
*
* */
bool binary_tree::is_complete(tree_node *root) {
queue<tree_node *> tree_que;
if(!root)
return true;
tree_que.push(root);
tree_node *tmp = tree_que.front();
while(tmp)
{
tree_que.pop();
tree_que.push(tmp->lchild);
tree_que.push(tmp->rchild);
tmp = tree_que.front();
}
tree_que.pop();// 把空pop出来
// 因为以经有一个空了,所以只要头不为空就不是完全二叉树
while(!tree_que.empty())
{
if(tree_que.front())
return false;
tree_que.pop();
}
return true;
}
int binary_tree::double_son_node(tree_node *root) {
if(root == nullptr)
return 0;
if(root->lchild && root->rchild)
return double_son_node(root->lchild)+double_son_node(root->rchild)+1;
else
return double_son_node(root->lchild)+double_son_node(root->rchild);
}
/*
* 交互二叉树的左右子树(后序遍历的应用)
* 1.首先交换root的左孩子的左右子树,
* 2.然后交换root的右孩子的左右子树
* 3.最后交换root的左右孩子,当结点为空时递归结束
*/
void binary_tree::swap_lrchild(tree_node *root) {
tree_node *tmp;
if(root)
{
swap_lrchild(root->lchild);
swap_lrchild(root->rchild);
tmp=root->lchild;
root->lchild=root->rchild;
root->rchild=tmp;
}
}
void binary_tree::swap_lrchild2(tree_node *root) {
tree_node *p, *tmp;
queue<tree_node *> tree_que;
if(root)
{
tree_que.push(root);
}
while(!tree_que.empty())
{
p = tree_que.front();
tree_que.pop();
if(p->lchild)
tree_que.push(p->lchild);
if(p->rchild)
tree_que.push(p->rchild);
tmp = p->lchild;
p->lchild = p->rchild;
p->rchild = tmp;
}
}
// 对应的博客中的代码有问题
// 715 行
int binary_tree::search_k_node(tree_node *root, int k) {
static int flg = 0;
static int ans = -1;
if(root)
{
flg++;
if(flg == k)
{
ans = root->data;
return ans;
}
search_k_node(root->lchild, k);
search_k_node(root->rchild, k);
}
return ans;
}
/**
* 思想很简单,但是destory_tree
* 写的删除不了根节点,这个代码就不测了
*
* */
void binary_tree::destory_x_node(tree_node *root, int k) {
if(root)
{
if(root->data == k)
{
destory_tree(root);
return;
}
queue<tree_node *> tree_que;
tree_que.push(root);
while(!tree_que.empty())
{
tree_node *tmp=tree_que.front();
tree_que.pop();
if(tmp->lchild)
{
if(tmp->lchild->data == k)
{
destory_tree(root->lchild);
root->lchild= nullptr;
}else
{
tree_que.push(tmp->lchild);
}
}
if(tmp->rchild)
{
if(tmp->rchild->data == k)
{
destory_tree(root->rchild);
root->rchild= nullptr;
}else
{
tree_que.push(tmp->rchild);
}
}
}
}
return;
}
/*
780 * 打印X结点的所有祖先,用到了非递归后序遍历的栈中信息
781 * 1.非递归后序遍历找到X
782 * 2.此时栈中的所有元素均为该结点的祖先结点
783 * Note:树上的代码是后序遍历的不同写法,感觉没必要记那种(应该看一下深入理解后序遍历),
784 * 会一种就够了了,所以我的代码,就是把上边的后序遍历中的输出语句该为了判断是否是当前结点。
785 * 王道 P.133 第十二题
博客中写的太恶心了,不要用那种
786 * */
void binary_tree::print_ancestor_node(tree_node *root, int x) {
stack<tree_node *> tree_stack;
tree_node *vis = nullptr;
if(!root)
{
cout << "tree is empyt" << endl;
return;
}
while(root || !tree_stack.empty())
{
if(root)
{
tree_stack.push(root);
root = root->lchild;
}else{
root = tree_stack.top();
if(root->rchild && root->rchild != vis)
{
root=root->rchild;
tree_stack.push(root);
root=root->lchild;
}else{
root=tree_stack.top();
tree_stack.pop();
/// 将后序遍历的输出改为判断是否为x节点
// 是x节点,跳出循环,栈中元素极为祖先
if(root->data == x)
break;
vis=root;
root=nullptr;
}
}
}
while(!tree_stack.empty())
{
cout << tree_stack.top()->data << endl;
tree_stack.pop();
}
return;
}
/*
829 * 求 p q两个结点的最近公共祖先,非递归后序遍历的应用,就是利用栈信息
830 * 假设p 在 q的左边
831 * 1.后序遍历必然先遍历到 p,这时把栈中的信息借用辅助栈保存起来
832 * 2.继续遍历,遍历到 q 结点的时候,将栈中的结点逐个和辅助栈的结点匹配,
833 * 第一个相等的元素就是p & q的最近公共祖先
834 * 王道 P.134 第13题
835 * */
tree_node *binary_tree::nearest_comm_ancestor(tree_node *root, int p, int q) {
stack<tree_node *> tree_stack;
stack<tree_node *> ass_tree_stack;
tree_node *vis = nullptr;
if(!root)
{
cout << "tree is empyt" << endl;
return nullptr;
}
while(root || !tree_stack.empty())
{
if(root)
{
tree_stack.push(root);
root = root->lchild;
}else{
root = tree_stack.top();
if(root->rchild && root->rchild != vis)
{
root=root->rchild;
tree_stack.push(root);
root=root->lchild;
}else{
root=tree_stack.top();
tree_stack.pop();
/// 将后序遍历的输出改为判断是否为x节点
// 是x节点,跳出循环,栈中元素极为祖先
if(root->data == p)
{
ass_tree_stack = tree_stack;
}
if(root->data == q)
{
vector<tree_node *> s1_info;
vector<tree_node *> s2_info;
while(!tree_stack.empty())
{
s1_info.push_back(tree_stack.top());
tree_stack.pop();
}
while(!ass_tree_stack.empty())
{
s2_info.push_back(ass_tree_stack.top());
ass_tree_stack.pop();
}
for (auto i=s1_info.begin(); i!=s1_info.end(); ++i) {
for (auto j = s2_info.begin(); j != s2_info.end() ; j++) {
if((*i) == (*j))
{
cout << *i << endl;
return *i;
}
}
}
}
vis=root;
root=nullptr;
}
}
}
return nullptr;
}
int binary_tree::tree_width(tree_node *root) {
queue<tree_node *> tree_queue;
if(!root)
return 0;
int tree_width=1;
tree_queue.push(root);
while(true)
{
int len = (int)tree_queue.size(); // 当前层具有的节点个数
if(len == 0)
break;
while(len > 0) // 如果当前层还有节点
{
tree_node *tmp = tree_queue.front();
tree_queue.pop(); // 出队,
len --;//长度减1
if(tmp->lchild)
tree_queue.push(tmp->lchild); // 下一层入队
if(tmp->rchild)
tree_queue.push(tmp->rchild); // 下一层入队
}
tree_width = max(tree_width,(int)tree_queue.size()); // 得到最大宽度
}
return tree_width;
}
/**
* 直接抄下来,没有细看
*
* */
void binary_tree::pre_to_post(int *pre, int s1, int e1, int *post, int s2, int e2) {
int mid;
if(e1>=s1)
{
post[e2]=pre[e1];
mid = (e1-s1)/2;
pre_to_post(pre, s1+1,s1+mid,post,s2,s2+mid-1);
pre_to_post(pre, s1+mid+1, e1, post, s1+mid, e2-1);
}
}
/**
*
* 没有细看
* */
tree_node *head, *pre= nullptr;
tree_node *binary_tree::inorder_list(tree_node *root) {
if(root)
{
inorder_list(root->lchild);
if(!root->lchild && !root->rchild)
{
if(!pre)
{
head = root;
pre = root;
}else{
pre->rchild = root;
pre = root;
}
inorder_list(root->rchild);
pre->rchild= nullptr;
}
}
return head;
}
/**
*
* 没有细看
* */
void binary_tree::link(tree_node *root, tree_node *head, tree_node *tail) {
if(root)
{
if(!root->lchild && !root->rchild)
{
if(!head)
{
head = root;
tail = root;
}else
{
tail->rchild = root;
tail = root;
}
}
link(root->lchild, head, tail);
link(root->rchild, head, tail);
}
}
bool binary_tree::is_similar(tree_node *root1, tree_node *root2) {
int l_data, r_data;
if(!root1 && !root2)
return true;
else if(!root1 && !root2)
return false;
else
{
l_data = is_similar(root1->lchild, root2->lchild);
r_data = is_similar(root1->lchild, root2->rchild);
return (l_data&&r_data);
}
}
int binary_tree::WPL(tree_node *node) {
return 0;
}
int main() {
// 1 2 0 0 3 0 4 5 0 0 0
// 1 0 2 0 0
std::cout << "Hello, World!" << std::endl;
binary_tree bt;
binary_tree bt1;
bt.root = bt.build_tree(1, "root");
bt1.root = bt1.build_tree(1, "root");
bt.pre_order(bt.root);
bt.in_order(bt.root);
bt.post_order(bt.root);
cout<< "node sum is : " << bt.sum_node(bt.root) << endl;
cout<< "leaf node sum is : " << bt.sum_leaf(bt.root) << endl;
cout<< "tree equals is : " << bt.tree_equals(bt.root, bt1.root) << endl;
// bt.destory_tree(bt.root);
// cout<< "node sum is : " << bt.sum_node(bt.root) << endl;
// cout << bt.root->data << endl;
binary_tree bt2;
bt2.root = bt.copy_tree(bt.root);
cout<< "node sum is : " << bt2.sum_node(bt2.root) << endl;
cout << bt2.tree_depth2(bt2.root)<< endl;
bt2.find_x_level(bt2.root, 2);
int A[] = {1,2,4,7,3,5,6,8};
int B[] = {4,7,2,1,5,3,8,6};
binary_tree bt3;
bt3.root = bt3.pre_in_create_tree2(A,B,0,7,0,7);
bt3.non_rec_pre_order(bt3.root);
cout << bt1.search_k_node(bt1.root, 15) << endl;
cout << bt1.nearest_comm_ancestor(bt1.root, 2,5)->data << endl;
bt1.pre_order(bt1.root);
cout << bt1.tree_width(bt1.root) << endl;
return 0;
}
一下两个版本部分代码存在问题,请忽略
///练练练
#include <stdio.h>
#include <stdlib.h>
typedef char Telemtype;
typedef struct BinTree{
Telemtype data;
struct BinTree *LChild;
struct BinTree *RChild;
}BinaryTree;
/*
* 建树是通过先序遍历的方法进行,先输如一个字符,如果不是‘0’,则进行
* 树的创建,否则不建树
* 树的创建需要有一下几个步骤
* 1.给树根结点申请空间
* 2.给根节点的数据域赋值
* 3.递归的分别创建左右子树
* */
BinaryTree* create_tree(BinaryTree *Tree)
{
Telemtype tmp;
scanf("%c", &tmp);
if(tmp == '0')
return 0;
Tree = (BinaryTree*)malloc(sizeof(BinaryTree));
Tree->data = tmp;
Tree->LChild = create_tree(Tree->LChild);
Tree->RChild = create_tree(Tree->RChild);
return Tree;
}
/*
* 递归写法的几种树的遍历(先序,中序,后序),都一样
* 但是这样的写法其实在其他操作中也类似,
* 1.比如说统计节点个数
* 2.树的销毁等等
* 对于时间复杂度,因为每个节点均遍历一次,所以复杂度为O(n)
* */
void preorder_traverse(BinaryTree *tree)
{
if(tree)
{
printf("%c ", tree->data);
preorder_traverse(tree->LChild);
preorder_traverse(tree->RChild);
}
}
void inorder_traverse(BinaryTree *tree)
{
if(tree)
{
inorder_traverse(tree->LChild);
printf("%c ", tree->data);
inorder_traverse(tree->RChild);
}
}
void postorder_traverse(BinaryTree *tree)
{
if(tree)
{
postorder_traverse(tree->LChild);
postorder_traverse(tree->RChild);
printf("%c ", tree->data);
}
}
/*
* 统计叶子节点的个数
* 1.先看当前节点是否是叶子节点,如果是叶子节点,sum值加一
* 2.然后递归的分别统计左右子树中拥有的叶子节点的个数
* */
int sum_left(BinaryTree *tree)
{
int sum = 0;
if(tree)
{
if(!tree->LChild && !tree->RChild)
sum ++;
if(tree->LChild)
sum += sum_left(tree->LChild);
if(tree->RChild)
sum += sum_left(tree->RChild);
}
return sum;
}
/*
* 1.如果两颗树是空树,则两颗树相等
* 2.否则,判断当前树的根节点是否相等
* 3.然后再递归的判断左右子树
* 4.如果都相同,返回1.否则返回0
* */
int is_equal(BinaryTree *T1, BinaryTree *T2)
{
if(!T1 && !T2)
{
return 1;
}
if(T1 && T2 && T1->data == T2->data)
if(is_equal(T1->LChild, T2->LChild))
if(is_equal(T1->RChild, T2->RChild))
return 1;
return 0;
}
/*
* 思路同后序遍历
* 1.先销毁左右子树
* 2.然后释放当前根节点的空间
* 3.将指针的指向 指到NULL
* Note:free(tree)仅仅收回内存,不会改变T的指向。
* */
void destory_tree(BinaryTree *tree)
{
if(tree == NULL)
return;
destory_tree(tree->LChild);
destory_tree(tree->RChild);
free(tree);
tree = NULL;
return;
}
/*
* 树的复制包含两部分,第一部分是,为根节点设置值和要指向的左右子树
* 第二部分就是递归的复制左右子树
* 左右子树的复制,还是同后序遍历
* */
BinaryTree *get_tree_node(Telemtype item, BinaryTree *LChild, BinaryTree *RChild)
{
BinaryTree *tree;
tree = (BinaryTree*)malloc(sizeof(BinaryTree));
tree->data = item;
tree->LChild = LChild;
tree->RChild = RChild;
return tree;
}
BinaryTree* copy_tree(BinaryTree *tree)
{
BinaryTree *newLChild, *newRChild, *newtree;
if(!tree)
return NULL;
if(tree->LChild)
newLChild = copy_tree(tree->LChild);
else
newLChild = NULL;
if(tree->RChild)
newRChild = copy_tree(tree->RChild);
else
newRChild = NULL;
newtree = get_tree_node(tree->data, newLChild, newRChild);
return newtree;
}
/*
* 非递归的遍历就要用到 Stack & Queue
* 1.Stack的初始化 stack.top = -1;
* 2.Queue的初始化 queue.front = queue.rear = 0;
* */
typedef struct TreeStack{
BinaryTree *stroe[1000];
int tag[1000]; //后序遍历要用到的标志域
int top;
}Tstack;
/*
*1.压栈操作,top+1 然后在当前位置存放节点信息
*2.出栈操作,返回当前栈顶元素,然后top-1
* */
void push_stack(Tstack *stack, BinaryTree *tree)
{
if(stack->top == 1000)
printf("the stack is full!\n");
else{
stack->top++;
stack->stroe[stack->top] = tree;
}
}
BinaryTree* pop_stack(Tstack *stack)
{
if(stack->top == -1)
return NULL;
else{
stack->top--;
return stack->stroe[stack->top+1];
}
}
typedef struct TreeQueue{
BinaryTree *stroe[1000];
int front;
int rear;
}Tqueue;
/*
* 入队,出队比较简单
* */
void enqueue(Tqueue *queue, BinaryTree *tree)
{
if(queue->rear == 1000)
printf("the queue is full!\n");
else{
queue->stroe[queue->rear] = tree;
queue->rear++;
}
}
BinaryTree* dequeue(Tqueue *queue)
{
if(queue->front == queue->rear)
return NULL;
else{
queue->front++;
return queue->stroe[queue->front-1];
}
}
/*
* Note: 请先参照中序遍历,中序遍历是教科书说法,比较准确
* 先序遍历的非递归算法和中序遍历的非递归算法类似
* 1.先访问当前根结点,并将根结点入栈,往左走
* 2.当当前节点没有左孩子时,将当前结点出栈,并访问他的右孩子
* 3.一直循环,直到栈空
* */
void non_recursion_preorder(BinaryTree *tree)
{
Tstack stack;
stack.top = -1;
if(!tree)
printf("the tree is empty!\n");
else{
while(tree || stack.top != -1)
{
if(tree)
{
printf("%c ", tree->data);
push_stack(&stack, tree);
tree = tree->LChild;
}else{
tree = pop_stack(&stack);
tree = tree->RChild;
}
/*
while(tree) //类似于中序遍历
{
printf("%c ", tree->LChild);
push_stack(&stack, tree);
tree = tree->LChild;
}
tree = pop_stack(&stack);
tree = tree->RChild;
* */
}
}
}
/*
* 1.先扫描(并非访问)根结点的所有左结点并将他们一一进栈
* 2.当当前结点没有左子树(或者左孩子结点已经访问过),将其出栈,访问他
* 3.然后扫描该结点的右孩子结点,将其进栈,再扫描右孩子结点的所有左结点并一一进栈,如此继续,直到栈空
* */
void non_recursion_inorder(BinaryTree *tree)
{
Tstack stack;
stack.top = -1;
if(!tree)
{
printf("the tree is empty!\n");
}else {
while(tree || stack.top != -1) //树根节点不空,或者栈不空时
{
if(tree){
push_stack(&stack, tree); //根结点进栈,遍历左子树
tree = tree->LChild; //每次遇到非空的左子树,就往左走
}else{
tree = pop_stack(&stack); //根指针退栈,访问根节点,遍历右子树
printf("%c ", tree->data);
tree = tree->RChild;
}
/*
while(tree) //另外一种好的写法,只要有左子树,就往左走
{
push_stack(&stack, tree); //根结点进栈,遍历左子树
tree = tree->LChild; //每次遇到非空的左子树,就往左走
}
tree = pop_stack(&stack); //根指针退栈,访问根节点,遍历右子树
printf("%c ", tree->data);
tree = tree->RChild;
* */
}
}
}
/*
* 后序遍历是先访问左右子树,最后访问根结点。
* 当用栈来存储结点时,必须分清返回根结点时,是从左结点返回的,还是从右结点返回的
* 用辅助指针可以写(也可以在结点中增加一个标志域)
* 1.从根结点一直向左走,直到没有左子树
* 2.转向向右走,先取栈顶指针
* 3.判断是否有右子树
* 4.若存在右子树且右子树是否被访问过,转向右子树,将右子树根结点压栈,继续走到最左边
* 5.不满足4,弹出当前根结点,进行访问,并做标记,将tmp置空,必须将tmp置空,跳过向左走,直接向右走
*
* Note:当访问一个结点 *tmp时,栈中的结点恰好是*tmp结点的所有祖先。
* 从栈底到栈顶结点再加上*tmp结点,刚好构成从根结点到*tmp的一条路径
* 在很多算法设计中都用到了这一特行,比如:
* *求根结点到某结点的路径
* *求两个结点的最近公共祖先
* */
void non_recursion_postorder(BinaryTree *tree)
{
Tstack stack;
stack.top = -1;
BinaryTree *tmp = tree;
BinaryTree *tag = NULL;
while(tmp || stack.top != -1)
{
if(tmp) //走到最左边
{
push_stack(&stack, tmp);
tmp = tmp->LChild;
}else{ //向右走
tmp = pop_stack(&stack); //取栈顶元素 这里应该是获取栈顶元素,但是不能出栈 王道 P.128
push_stack(&stack, tmp);
if(tmp->RChild && tmp->RChild != tag) //如果右子树存在,且未被访问过
{
tmp = tmp->RChild; //转向右子树
push_stack(&stack, tmp); //压栈
tmp = tmp->LChild; //继续走到最左边
}else{ //如果右子树不存在,或者已经访问过
tmp = pop_stack(&stack); //弹出当前的根结点
printf("%c ", tmp->data); //进行访问
tag = tmp; //标记访问过
tmp = NULL; //访问过后,重置tmp指针,必须将tmp置空,跳过向左走,直接向右走
}
}
}
}
//后序遍历的标记数据域标记写法
void non_recursion_postorder2(BinaryTree *tree)
{
Tstack stack;
stack.top = -1;
if(!tree)
printf("the tree is empty!\n");
else{
while(tree || stack.top != -1) {
while (tree) {
push_stack(&stack, tree);
stack.tag[stack.top] = 0; //设置访问标记,0为第一次访问,1为第二次访问
tree = tree->LChild;
}
if (stack.tag[stack.top] == 0) //第一次访问时,转向同层右结点
{
tree = stack.stroe[stack.top]; //左走到底时,tree是空,必须有这句话
stack.tag[stack.top] = 1;
tree = tree->RChild;
} else {
while (stack.tag[stack.top] == 1)//在栈中找到下一个第一次范格纹你的结点,退出循环时并没有pop,所以为其左子结点
{
tree = pop_stack(&stack);
printf("%c ", tree->data);
}
tree = NULL;
}
}
}
}
/*
* 层次遍历,其实就是BFS (广度优先搜索)
* */
void levelorder(BinaryTree *tree)
{
Tqueue queue;
queue.front = queue.rear = 0;
enqueue(&queue, tree); //根结点入队
while(queue.front != queue.rear) { //队列不为空时,循环
tree = dequeue(&queue); //队头元素出队
printf("%c ", tree->data); //访问当前结点
if (tree->LChild != NULL)
enqueue(&queue, tree->LChild);
if (tree->RChild != NULL)
enqueue(&queue, tree->RChild);
}
}
/*
* 层次遍历的应用,将树自下而上,自右向左遍历,
* 就是把层次遍历访问的结点入栈,然后从栈弹出的顺序
* 王道 P.128
* */
void invert_levelorder(BinaryTree *tree)
{
Tqueue queue;
Tstack stack;
if(tree != NULL)
{
stack.top = -1;
queue.front = queue.rear = 0;
enqueue(&queue, tree); //根结点入队
while(queue.front != queue.rear) {
tree = dequeue(&queue);
push_stack(&stack, tree); //当前结点 入栈
if (tree->LChild != NULL)
enqueue(&queue, tree->LChild);
if (tree->RChild != NULL)
enqueue(&queue, tree->RChild);
}
while(stack.top != -1)
{
tree = pop_stack(&stack);
printf("%c ", tree->data);
}
}
}
/*
* 王道 第五题 P.129 通过层次遍历获得树的深度
* */
int tree_depth(BinaryTree *tree)
{
if(!tree)
return 0;
Tqueue queue;
queue.front = queue.rear = 0;
int last = 1, level = 0; //last指向下一层的第一个结点
enqueue(&queue, tree); //根结点入队
while(queue.front != queue.rear)
{
tree = dequeue(&queue);
if(tree->LChild)
enqueue(&queue, tree->LChild);
if(tree->RChild)
enqueue(&queue, tree->RChild);
//好好理解这里
if(queue.front == last) //处理该层的最右结点
{
level++; //层数加一
last = queue.rear; //last指向下层
}
}
return level;
}
int max(int a, int b)
{
return (a > b) ? a : b;
}
/*
* 统计树的深度,同后序遍历
* 1.如果树空,深度为零
* 2.否则分别递归求解左右子树的深度
* 3.树的深度为 1+左右子树中更大的深度
* */
int tree_depth2(BinaryTree *tree)
{
int d = 0, dl, dr;
if(!tree)
d = 0;
else
{
dl = tree_depth2(tree->LChild);
dr = tree_depth2(tree->RChild);
d = 1 + max(dl, dr);
}
return d;
}
/*
* NOTE: 关键的地方还是区间划分
* */
BinaryTree* pre_in_create_tree2(Telemtype A[], Telemtype B[], int start1, int end1, int start2, int end2)
{
if(start1 > end1 || start2 > end2)
return NULL;
BinaryTree *tree;
tree = (BinaryTree*)malloc(sizeof(BinaryTree));
tree->data = A[start1]; //根结点
for(int i = start2; i <=end2; i++) //根结点在中序中的划分
{
if(A[start1] == B[i]) {
tree->LChild = pre_in_create_tree2(A, B, start1 + 1, start1 + i - start2, start2, i - 1);
tree->RChild = pre_in_create_tree2(A, B, i - start2 + start1 + 1, end1, i + 1, end2);
}
}
return tree;
}
/*
* 由先序和中序遍历,来唯一确定一棵二叉树
* 1.根据先序序列确定树的根结点
* 2.根据根结点在中序遍历中划分左右子树,然后根据左右子树结点在先序序列中的次序,可以确定子树的根结点,(即回到第一步)
* 王道书上 P.130 第六题
* */
BinaryTree* pre_in_create_tree(Telemtype A[], Telemtype B[], int startPre, int endPre, int startIn, int endIn)
{
int i;
BinaryTree *tree;
tree = (BinaryTree*)malloc(sizeof(BinaryTree));
tree->data = A[startPre];
for(i = startIn; B[i]!=tree->data; ++i);
int LChild_len = i - startIn; //左子树的长度
int RChild_len = endIn - i; //右子树的长度
if(LChild_len) //递归建立左子树
tree->LChild = pre_in_create_tree(A, B, startPre+1, startPre+LChild_len, startIn, startIn+LChild_len-1); //划分的区间,是值得注意的地方
else
tree->LChild = NULL;
if(RChild_len) //递归建立右子树
tree->RChild = pre_in_create_tree(A, B, endPre-RChild_len+1, endPre, endIn-RChild_len+1, endIn);
else
tree->RChild = NULL;
return tree;
}
/*
* 层次遍历的应用
* 1.将所有结点入队列(包括空结点)。
* 2.当遇到空结点时,判断其后是否存在非空结点,如果存在,则不是完全二叉树
* 王道 P.131 第七题
* */
bool is_complete(BinaryTree *tree)
{
Tqueue queue;
queue.front = queue.rear = 0;
if(!tree)
return 1; //空树为满二叉树
enqueue(&queue, tree);
while(queue.front != queue.rear)
{
if(!tree) //结点非空,将其左右子树入队
{
enqueue(&queue, tree->LChild);
enqueue(&queue, tree->RChild);
} else { //结点非空,检查其后是否有非空结点
while(queue.front != queue.rear)
{
tree = dequeue(&queue);
if(tree) //结点非空,为非完全二叉树
return 0;
}
}
}
return 1;
}
/*
* 统计双分支结点的个数
* 递归思路
* f(root) = 0; 若root == NULL
* f(root) = f(root->LChild) + f(root->RChild) + 1; 当前root结点为双分支结点
* f(root) = f(root->LChild) + f(root->RChild); 其他情况(当前root为单分支结点,或者root为叶子结点)
* 王道P.131 第八题
* */
int double_son_node(BinaryTree *tree)
{
if(tree == NULL)
return 0;
if(tree->LChild != NULL && tree->RChild != NULL)
{
return double_son_node(tree->LChild) + double_son_node(tree->RChild) + 1;
}else {
double_son_node(tree->LChild) + double_son_node(tree->RChild);
}
}
/*
* 交互二叉树的左右子树(后序遍历的应用)
* 1.首先交换root的左孩子的左右子树,
* 2.然后交换root的右孩子的左右子树
* 3.最后交换root的左右孩子,当结点为空时递归结束
* 王道 P.131 第九题
* */
void swap_lrchild(BinaryTree *tree)
{
BinaryTree *tmp;
if(tree)
{
swap_lrchild(tree->LChild);
swap_lrchild(tree->RChild);
tmp = tree->LChild;
tree->LChild = tree->RChild;
tree->RChild = tmp;
}
}
/*
* 求先序遍历中的第k个结点的值(确保k值在有效范围内)
* 1.设置一个全局变量itag记录访问过的结点的序号,其初值是根结点在先序序列中的序号,即为1
* 2.当二叉树tree为空时,返回特殊结点“#”,当itag == k时,表示找到了满足条件的结点,返回 tree->data
* 3.当itag != k 是,则递归的在左右子树中继续查找
* 王道 P.131 第十题
* */
int itag = 1;
Telemtype search_k_node(BinaryTree *tree, int k)
{
if(tree == NULL)
return '#';
if(itag == k)
return tree->data;
itag++;
Telemtype ch = search_k_node(tree->LChild, k);
if(tree->LChild != NULL)
return ch;
ch = search_k_node(tree->RChild, k);
if(tree->RChild != NULL) //确保一定有返回值
return ch;
else
return '#';
}
/*
* 层次遍历的基本思想,就是找到 X 结点,然后删除它这棵树
* 1.如果当前树根为X结点,直接删掉
* 2.否则,进行层次遍历,去找 X,找到了就删掉,
* Note:应为之前封装的好,明显要比书上的代码形式统一,也好看的多
* 王道 P.132 第十一题
* */
void destroy_x_tree(BinaryTree *tree, Telemtype x)
{
if(tree)
{
if(tree->data == x)
{
destory_tree(tree);
return;
}
Tqueue queue;
queue.front = queue.rear = 0;
enqueue(&queue, tree);
while(queue.front != queue.rear)
{
tree = dequeue(&queue);
if(tree->LChild)
{
if(tree->LChild->data == x)
{
destory_tree(tree->LChild);
tree->LChild = NULL;
} else {
enqueue(&queue, tree->LChild);
}
}
if(tree->RChild)
{
if(tree->RChild->data == x)
{
destory_tree(tree->RChild);
tree->RChild = NULL;
}else{
enqueue(&queue, tree->RChild);
}
}
}
}
return;
}
/*
* 打印X结点的所有祖先,用到了非递归后序遍历的栈中信息
* 1.非递归后序遍历找到X
* 2.此时栈中的所有元素均为该结点的祖先结点
* Note:树上的代码是后序遍历的不同写法,感觉没必要记那种(应该看一下深入理解后序遍历),
* 会一种就够了了,所以我的代码,就是把上边的后序遍历中的输出语句该为了判断是否是当前结点。
* 王道 P.133 第十二题
* */
void print_ancestor_node(BinaryTree *tree, Telemtype x)
{
Tstack stack;
stack.top = -1;
if(!tree)
printf("the tree is empty!\n");
else{
while(tree || stack.top != -1) {
while (tree) {
push_stack(&stack, tree);
stack.tag[stack.top] = 0; //设置访问标记,0为第一次访问,1为第二次访问
tree = tree->LChild;
}
if (stack.tag[stack.top] == 0) //第一次访问时,转向同层右结点
{
tree = stack.stroe[stack.top]; //左走到底时,tree是空,必须有这句话
stack.tag[stack.top] = 1;
tree = tree->RChild;
} else {
while (stack.tag[stack.top] == 1)//在栈中找到下一个第一次范格纹你的结点,退出循环时并没有pop,所以为其左子结点
{
tree = pop_stack(&stack);
if(tree->data == x)
{
printf("\n%c ancestor is : \n",tree->data);;
for(int i = 0; i <= stack.top; ++i)
{
printf("%c ", stack.stroe[i]->data);
}
return;
}
}
tree = NULL;
}
}
}
}
/*
* 2016/9/1 今天就写到这里,感觉自己对后序遍历的非递归算法,理解不够。
* 先不写了回头总结总结
* */
int main()
{
BinaryTree *tree;
tree = create_tree(tree);
printf("preorder\n");
//preorder_traverse(tree);
non_recursion_preorder(tree);
printf("\ninorder\n");
//inorder_traverse(tree);
non_recursion_inorder(tree);
printf("\npostorder\n");
//postorder_traverse(tree);
non_recursion_postorder(tree);
printf("\nlevelorder\n");
levelorder(tree);
printf("\ninvert_levelorder\n");
invert_levelorder(tree);
printf("\nleft_node`s number is %d\n", sum_left(tree));
printf("\ndepth is %d\n", tree_depth2(tree));
printf("\ndepth is %d\n", tree_depth(tree));
//Telemtype A[] = {'A','B','C','D','E','F','G','H','K'};
//Telemtype B[] = {'B','D','C','A','E','H','G','K','F'};
Telemtype A[] = {' ','1','2','4','7','3','5','6','8'};
Telemtype B[] = {' ','4','7','2','1','5','3','8','6'};
BinaryTree *root, *root2;
root = pre_in_create_tree(A, B, 1, 8, 1, 8);
puts("\n*********************root traverse\n");
preorder_traverse(root);
root2 = pre_in_create_tree2(A, B, 1, 8, 1, 8);
puts("\n*********************root2 traverse\n");
preorder_traverse(root2);
printf("is complete %d\n", is_complete(root));
printf("double son node is %d\n", double_son_node(root));
swap_lrchild(root2);
preorder_traverse(root2);
printf("\n%c\n", search_k_node(root2, 4));
destroy_x_tree(root2, '2');
preorder_traverse(root2);
puts("\nprint_ancestor_node");
print_ancestor_node(root, '5');
printf("\n\nend!!\n\n");
return 0;
}
更新一些代码
1 ///练练练 2 #include <stdio.h> 3 #include <stdlib.h> 4 typedef char Telemtype; 5 typedef struct BinaryTree{ 6 Telemtype data; 7 struct BinaryTree *LChild; 8 struct BinaryTree *RChild; 9 }BinaryTree; 10 /* function content 11 * 12 * BinaryTree *create_tree(BinaryTree *root) 13 * preorder_traverse(BinaryTree *root) 14 * void inorder_traverse(BinaryTree *root) 15 * void postorder_traverse(BinaryTree *root) 16 * int sum_node(BinaryTree *root) 17 * int tree_equal(BinaryTree *T1, BinaryTree *T2) 18 * void destory_tree(BinaryTree *root) 19 * BinaryTree *copy_tree(BinaryTree *root) 20 * void non_recursion_preorder(BinaryTree *root) 21 * void non_recursion_inorder(BinaryTree *root) 22 * void non_recursion_postorder(BinaryTree *root) 23 * void non_recursion_postorder2(BinaryTree *root) 24 * void levelorder(BinaryTree *root) 25 * void invert_levelorder(BinaryTree *root) 26 * int tree_depth(BinaryTree *root) 27 * int tree_depth2(BinaryTree *root) 28 * void search_x_level(BinaryTree *root, Telemtype x) 29 * BinaryTree *pre_in_create_tree(Telemtype A[], Telemtype B[], int startPre, int endPre, int startIn, int endIn) 30 * BinaryTree *pre_in_create_tree2(Telemtype A[], Telemtype B[], int s1, int e1, int s2, int e2) 31 * int is_complete(BinaryTree *root) 32 * int double_son_node(BinaryTree *tree) 33 * void swap_lrchild(BinaryTree *tree) 34 * void swap_lrchild2(BinaryTree *root) 35 * Telemtype search_k_node(BinaryTree *tree, int k) 36 * void destroy_x_tree(BinaryTree *tree, Telemtype x) 37 * void print_ancestor_node(BinaryTree *tree, Telemtype x) 38 * BinaryTree *nearest_comm_ancestor(BinaryTree *tree, Telemtype p, Telemtype q) 39 * int tree_width(BinaryTree *root) 40 * void pre_to_post(Telemtype pre[], int s1, int e1, Telemtype post[], int s2, int e2) 41 * BinaryTree *inorder_List(BinaryTree *root) 42 * void link(BinaryTree *root, BinaryTree *head, BinaryTree *tail) 43 * int is_similar(BinaryTree *T1, BinaryTree *T2) 44 * int WPL(BinaryTree *root) 45 * */ 46 /* 47 * 建树是通过先序遍历的方法进行,先输如一个字符,如果不是‘0’,则进行 48 * 树的创建,否则不建树 49 * 树的创建需要有一下几个步骤 50 * 1.给树根结点申请空间 51 * 2.给根节点的数据域赋值 52 * 3.递归的分别创建左右子树 53 * */ 54 BinaryTree *create_tree(BinaryTree *root) 55 { 56 Telemtype tmp; 57 scanf("%c", &tmp); 58 if(tmp == '0') 59 return NULL; 60 root = (BinaryTree*)malloc(sizeof(BinaryTree)); 61 root->data = tmp; 62 root->LChild = create_tree(root->LChild); 63 root->RChild = create_tree(root->RChild); 64 return root; 65 } 66 67 /* 68 * 递归写法的几种树的遍历(先序,中序,后序),都一样 69 * 但是这样的写法其实在其他操作中也类似, 70 * 1.比如说进行统计节点个数 71 * 2.树的销毁等等 72 * 对于时间复杂度,因为每个节点均遍历一次,所以复杂度为O(n) 73 * */ 74 void preorder_traverse(BinaryTree *root) 75 { 76 if(root) 77 { 78 printf("%c ", root->data); 79 preorder_traverse(root->LChild); 80 preorder_traverse(root->RChild); 81 } 82 } 83 84 void inorder_traverse(BinaryTree *root) 85 { 86 if(root) 87 { 88 inorder_traverse(root->LChild); 89 printf("%c ", root->data); 90 inorder_traverse(root->RChild); 91 } 92 } 93 94 void postorder_traverse(BinaryTree *root) 95 { 96 if(root) 97 { 98 postorder_traverse(root->LChild); 99 postorder_traverse(root->RChild); 100 printf("%c ", root->data); 101 } 102 } 103 /* 104 * 统计二叉树中结点的个数 105 * */ 106 int sum_node(BinaryTree *root) 107 { 108 if(!root) //root == NULL 109 return 0; 110 else{ 111 return sum_node(root->LChild) 112 + sum_node(root->RChild) + 1; 113 } 114 } 115 116 /* 117 * 统计叶子节点的个数 118 * 1.先看当前节点是否是叶子节点,如果是叶子节点,sum值加一 119 * 2.然后递归的分别统计左右子树中拥有的叶子节点的个数 120 * */ 121 int sum_leaf(BinaryTree *root) 122 { 123 int sum = 0; 124 if(root) 125 { 126 if(!root->LChild && !root->RChild) 127 sum ++; 128 if(root->LChild) 129 sum += sum_leaf(root->LChild); 130 if(root->RChild) 131 sum += sum_leaf(root->RChild); 132 } 133 return sum; 134 } 135 /* 136 * 1.如果两颗树是空树,则两颗树相等 137 * 2.否则,判断当前树的根节点是否相等 138 * 3.然后再递归的判断左右子树 139 * 4.如果都相同,发回1.否则返回0 140 * */ 141 int tree_equal(BinaryTree *T1, BinaryTree *T2) 142 { 143 if(!T1 && !T2) 144 return 1; 145 146 if(T1 && T2 && T1->data == T2->data) 147 if(tree_equal(T1->LChild, T2->LChild)) 148 if(tree_equal(T1->RChild, T2->RChild)) 149 return 1; 150 return 0; 151 } 152 /* 153 * 思路同后序遍历 154 * 1.先销毁左右子树 155 * 2.然后释放当前根节点的空间 156 * 3.将指针的指向 指到NULL 157 * Note:free(tree)仅仅收回内存,不会改变T的指向。 158 * */ 159 void destory_tree(BinaryTree *root) 160 { 161 if(!root) 162 return; 163 164 destory_tree(root->LChild); 165 destory_tree(root->RChild); 166 free(root); 167 root = NULL; 168 return; 169 } 170 171 /* 172 * 树的复制包含两部分,一部分是,为要根节点设置值和要指向的左右子树 173 * 第二部分就是递归的复制左右子树 174 * 左右子树的复制,还是同后序遍历 175 * */ 176 BinaryTree *get_tree_node(Telemtype data, BinaryTree *LChild, BinaryTree *RChild) 177 { 178 BinaryTree *root; 179 root = (BinaryTree*)malloc(sizeof(BinaryTree)); 180 root->data = data; 181 root->LChild = LChild; 182 root->RChild = RChild; 183 return root; 184 } 185 186 BinaryTree *copy_tree(BinaryTree *root) 187 { 188 BinaryTree *newLChild, *newRChild, *newRoot; 189 if(!root) 190 return NULL; 191 192 if(root->LChild) 193 newLChild = copy_tree(root->LChild); 194 else 195 newLChild = NULL; 196 if(root->RChild) 197 newRChild = copy_tree(root->RChild); 198 else 199 newRChild = NULL; 200 201 newRoot = get_tree_node(root->data, newLChild, newRChild); 202 203 return newRoot; 204 } 205 206 /* 207 * 非递归的遍历就要用到 Stack & Queue 208 * 1.Stack的初始化 stack.top = -1; 209 * 2.Queue的初始化 queue.front = queue.rear = 0; 210 * */ 211 typedef struct TreeStack{ 212 BinaryTree *stroe[1000]; 213 int tag[1000]; //后序遍历要用到的标志域 214 int top; 215 }Tstack; 216 /* 217 *1.压栈操作,top+1 然后在当前位置存放节点信息 218 *2.出栈操作,返回当前栈顶元素,然后top-1 219 * */ 220 void push_stack(Tstack *stack, BinaryTree *root) 221 { 222 if(stack->top == 1000) 223 printf("the stack is full!\n"); 224 else{ 225 stack->top++; 226 stack->stroe[stack->top] = root; 227 } 228 } 229 230 BinaryTree* pop_stack(Tstack *stack) 231 { 232 if(stack->top == -1) 233 return NULL; 234 else{ 235 stack->top--; 236 return stack->stroe[stack->top+1]; 237 } 238 } 239 240 typedef struct TreeQueue{ 241 BinaryTree *stroe[1000]; 242 int level[1000]; 243 int front; 244 int rear; 245 }Tqueue; 246 /* 247 * 入队,出队比较简单 248 * */ 249 void enqueue(Tqueue *queue, BinaryTree *root) 250 { 251 if(queue->rear == 1000) 252 printf("the queue is full!\n"); 253 else{ 254 queue->stroe[queue->rear] = root; 255 queue->rear++; 256 } 257 } 258 259 BinaryTree* dequeue(Tqueue *queue) 260 { 261 if(queue->front == queue->rear) 262 return NULL; 263 else{ 264 queue->front++; 265 return queue->stroe[queue->front-1]; 266 } 267 268 } 269 /* 270 * Note: 请先参照中序遍历,中序遍历是教科书说法,比较准确 271 * 先序遍历的非递归算法和中序遍历的非递归算法类似 272 * 1.先访问当前根结点,并将根结点入栈,往左走 273 * 2.当当前节点没有左孩子时,将当前结点出栈,并访问他的右孩子 274 * 3.一直循环,直到栈空 275 * */ 276 void non_recursion_preorder(BinaryTree *root) 277 { 278 Tstack stack; 279 stack.top = -1; 280 if(!root) 281 printf("the tree is empty!\n"); 282 else{ 283 while(root || stack.top != -1) 284 { 285 if(root) 286 { 287 printf("%c ", root->data); 288 push_stack(&stack, root); 289 root = root->LChild; 290 }else{ 291 root = pop_stack(&stack); 292 root = root->RChild; 293 } 294 /* 295 while(root) //类似于中序遍历,详见下边 296 { 297 printf("%c ", root->LChild); 298 push_stack(&stack, root); 299 root = root->LChild; 300 } 301 root = pop_stack(&stack); 302 root = root->RChild; 303 * */ 304 } 305 } 306 } 307 308 /* 309 * 1.先扫描(并非访问)根结点的所有左结点并将他们一一进栈 310 * 2.当当前结点没有左子树(或者做孩子结点已经访问过),将其出栈,访问他 311 * 3.然后扫描该结点的右孩子结点,将其进栈,再扫描右孩子结点的所有左结点并一一进栈,如此继续,直到栈空 312 * */ 313 void non_recursion_inorder(BinaryTree *root) 314 { 315 Tstack stack; 316 stack.top = -1; 317 if(!root) 318 { 319 printf("the tree is empty!\n"); 320 }else { 321 while(root || stack.top != -1) //树根节点不空,或者栈不空时 322 { 323 if(root){ 324 push_stack(&stack, root); //根结点进栈,遍历左子树 325 root = root->LChild; //每次遇到非空的左子树,就往左走 326 }else{ 327 root = pop_stack(&stack); //根指针退栈,访问根节点,遍历右子树 328 printf("%c ", root->data); 329 root = root->RChild; 330 } 331 332 /* 333 while(root) //另外一种好的写法,只要有左子树,就往左走 334 { 335 push_stack(&stack, root); //根结点进栈,遍历左子树 336 root = root->LChild; //每次遇到非空的左子树,就往左走 337 } 338 root = pop_stack(&stack); //根指针退栈,访问根节点,遍历右子树 339 printf("%c ", root->data); 340 root = root->RChild; 341 * */ 342 } 343 } 344 } 345 346 /* 347 * 后序遍历是先访问左右子树,最后访问根结点。 348 * 当用栈来存储结点时,必须分清返回根结点时,是从左结点返回的,还是从右结点返回的 349 * 用辅助指针可以写(也可以在结点中增加一个标志域) 350 * 1.从根结点一直向左走,直到没有左子树 351 * 2.转向向右走,先取栈顶指针 352 * 3.判断是否有右子树 353 * 4.若存在右子树且右子树是否被访问过,转向右子树,将右子树根结点压栈,继续走到最左边 354 * 5.不满足4,弹出当前根结点,进行访问,并做标记,将root置空,必须将root置空,跳过向左走,直接向右走 355 * 356 * Note:当访问一个结点 *tmp (就是当前root)时,栈中的结点恰好是*tmp结点的所有祖先。 357 * 从栈底到栈顶结点再加上*tmp结点,刚好构成从根结点到*tmp的一条路径 358 * 在很多算法设计中都用到了这一特行,比如: 359 * *求根结点到某结点的路径 360 * *求两个结点的最近公共祖先 361 * */ 362 363 void non_recursion_postorder(BinaryTree *root) 364 { 365 Tstack stack; 366 stack.top = -1; 367 BinaryTree *vis = NULL; 368 369 if(!root) 370 printf("the tree is empty!\n"); 371 372 while(root || stack.top != -1) 373 { 374 if(root) //走到最左边 375 { 376 push_stack(&stack, root); 377 root = root->LChild; 378 }else{ //向右走 379 root = stack.stroe[stack.top]; //取栈顶元素 王道 P.128 380 if(root->RChild && root->RChild != vis) //如果右子树存在,且未被访问过 381 { 382 root = root->RChild; //转向右子树 383 push_stack(&stack, root); //压栈 384 root = root->LChild; //继续走到最左边 385 }else{ //如果右子树不存在,或者已经访问过 386 root = pop_stack(&stack); //弹出当前的根结点 387 printf("%c ", root->data); //进行访问 388 vis = root; //标记访问过 389 root = NULL; //访问过后,重置root指针,必须将root置空,跳过向左走,直接向右走 390 } 391 } 392 } 393 } 394 395 //后序遍历的标记数据域标记写法,这个不推荐 396 void non_recursion_postorder2(BinaryTree *root) 397 { 398 Tstack stack; 399 stack.top = -1; 400 if(!root) 401 printf("the tree is empty!\n"); 402 else{ 403 while(root || stack.top != -1) { 404 while (root) { 405 push_stack(&stack, root); 406 stack.tag[stack.top] = 0; //设置访问标记,0为第一次访问,1为第二次访问 407 root = root->LChild; 408 } 409 if (stack.tag[stack.top] == 0) //第一次访问时,转向同层右结点 410 { 411 root = stack.stroe[stack.top]; //左走到底时,tree是空,必须有这句话 412 stack.tag[stack.top] = 1; 413 root = root->RChild; 414 } else { 415 while (stack.tag[stack.top] == 1)//在栈中找到下一个第一次范格纹你的结点,退出循环时并没有pop,所以为其左子结点 416 { 417 root = pop_stack(&stack); 418 printf("%c ", root->data); 419 } 420 root = NULL; 421 } 422 } 423 } 424 } 425 426 /* 427 * 层次遍历,其实就是BFS (广度优先搜索) 428 * */ 429 void levelorder(BinaryTree *root) 430 { 431 Tqueue queue; 432 queue.front = queue.rear = 0; 433 434 if(!root) 435 printf("the tree is empty!\n"); 436 437 enqueue(&queue, root); //根结点入队 438 439 while(queue.front != queue.rear) 440 { //队列不为空时,循环 441 root = dequeue(&queue); //队头元素出队 442 printf("%c ", root->data); //访问当前结点 443 444 if (root->LChild != NULL) 445 enqueue(&queue, root->LChild); 446 447 if (root->RChild != NULL) 448 enqueue(&queue, root->RChild); 449 } 450 } 451 /* 452 * 层次遍历的应用,将树自下而上,自右向左遍历, 453 * 就是把层次遍历访问的结点入栈,然后从栈弹出的顺序 454 * 王道 P.128 455 * */ 456 void invert_levelorder(BinaryTree *root) 457 { 458 Tqueue queue; 459 Tstack stack; 460 461 if(!root) 462 printf("the tree is empty!\n"); 463 464 stack.top = -1; 465 queue.front = queue.rear = 0; 466 enqueue(&queue, root); //根结点入队 467 468 while(queue.front != queue.rear) 469 { 470 root = dequeue(&queue); 471 push_stack(&stack, root); //当前结点 入栈 472 473 if (root->LChild != NULL) 474 enqueue(&queue, root->LChild); 475 476 if (root->RChild != NULL) 477 enqueue(&queue, root->RChild); 478 } 479 480 while(stack.top != -1) 481 { 482 root = pop_stack(&stack); 483 printf("%c ", root->data); 484 } 485 } 486 /* 487 * 王道 第五题 P.129 通过层次遍历获得树的深度 488 * */ 489 int tree_depth(BinaryTree *root) 490 { 491 Tqueue queue; 492 493 if(!root) 494 return 0; 495 496 queue.front = queue.rear = 0; 497 int last = 1, level = 0; //last指向下一层的第一个结点 498 enqueue(&queue, root); //根结点入队 499 500 while(queue.front != queue.rear) 501 { 502 root = dequeue(&queue); 503 504 if(root->LChild) 505 enqueue(&queue, root->LChild); 506 if(root->RChild) 507 enqueue(&queue, root->RChild); 508 509 //好好理解这里 510 if(queue.front == last) //处理该层的最右结点 511 { 512 level++; //层数加一 513 last = queue.rear; //last指向下层 514 } 515 } 516 return level; 517 } 518 519 int max(int a, int b) 520 { 521 return (a > b) ? a : b; 522 } 523 /* 524 * 统计树的深度,同后序遍历 525 * 1.如果树空,深度为零 526 * 2.否则分别递归求解左右子树的深度 527 * 3.树的深度为 1+左右子树中更大的深度 528 * */ 529 int tree_depth2(BinaryTree *root) 530 { 531 int d = 0, dl, dr; 532 if(!root) 533 d = 0; 534 else 535 { 536 dl = tree_depth2(root->LChild); 537 dr = tree_depth2(root->RChild); 538 d = 1 + max(dl, dr); 539 } 540 return d; 541 } 542 543 /* 544 *求二叉树中值为x的结点所在的层数 545 * */ 546 void search_x_level(BinaryTree *root, Telemtype x) 547 { 548 static int level = 1; 549 if(root) 550 { 551 if(root->data == x) 552 printf("the x level is %d\n", level) ; 553 level++; 554 search_x_level(root->LChild, x); 555 search_x_level(root->RChild, x); 556 level--; 557 } 558 } 559 560 /* 561 * 下面这种写法,牛逼666,学这个 562 * NOTE: 关键的地方还是区间划分 563 * s1 : start1, e1 : end1 564 * s2 : start2, e2 : end2 565 * */ 566 BinaryTree *pre_in_create_tree2(Telemtype A[], Telemtype B[], int s1, int e1, int s2, int e2) 567 { 568 if(s1 > e1 || s2 > e2) 569 return NULL; 570 BinaryTree *root; 571 root = (BinaryTree*)malloc(sizeof(BinaryTree)); 572 root->data = A[s1]; //根结点 573 for(int i = s2; i <=e2; i++) //根结点在中序中的划分 574 { 575 if(A[s1] == B[i]) { 576 root->LChild = pre_in_create_tree2(A, B, s1 + 1, s1 + i - s2, s2, i - 1); 577 root->RChild = pre_in_create_tree2(A, B, i - s2 + s1 + 1, e1, i + 1, e2); 578 } 579 } 580 return root; 581 } 582 583 /* 584 * 由先序和中序遍历,来唯一确定一棵二叉树 585 * 1.根据先序序列确定树的根结点 586 * 2.根据根结点在中序遍历中划分左右子树,然后根据左右子树结点在先序序列中的次序,可以确定子树的根结点,(即回到第一步) 587 * 王道书上 P.130 第六题 588 * */ 589 BinaryTree *pre_in_create_tree(Telemtype A[], Telemtype B[], int startPre, int endPre, int startIn, int endIn) 590 { 591 int i; 592 BinaryTree *root; 593 root = (BinaryTree*)malloc(sizeof(BinaryTree)); 594 root->data = A[startPre]; 595 for(i = startIn; B[i]!=root->data; ++i); 596 int LChild_len = i - startIn; //左子树的长度 597 int RChild_len = endIn - i; //右子树的长度 598 599 if(LChild_len) //递归建立左子树 600 root->LChild = pre_in_create_tree(A, B, startPre+1, startPre+LChild_len, startIn, startIn+LChild_len-1); //划分的区间,是值得注意的地方 601 else 602 root->LChild = NULL; 603 604 if(RChild_len) //递归建立右子树 605 root->RChild = pre_in_create_tree(A, B, endPre-RChild_len+1, endPre, endIn-RChild_len+1, endIn); 606 else 607 root->RChild = NULL; 608 609 return root; 610 } 611 /* 612 * 层次遍历的应用 613 * 1.将所有结点加入队列(包括空结点)。 614 * 2.当遇到空结点时,判断其后是否存在非空结点,如果存在,则不是完全二叉树 615 * 王道 P.131 第七题 616 * */ 617 int is_complete(BinaryTree *root) 618 { 619 Tqueue queue; 620 621 if(!root) 622 return 1; //空树为满二叉树 623 624 queue.front = queue.rear = 0; 625 enqueue(&queue, root); 626 627 while(queue.front != queue.rear) 628 { 629 if(!root) //结点非空,将其左右子树入队 630 { 631 enqueue(&queue, root->LChild); 632 enqueue(&queue, root->RChild); 633 } else { //结点非空,检查其后是否有非空结点 634 while(queue.front != queue.rear) 635 { 636 root = dequeue(&queue); 637 if(root) //结点非空,为非完全二叉树 638 return 0; 639 } 640 } 641 } 642 return 1; 643 } 644 /* 645 * 统计双分支结点的个数 646 * 递归思路 647 * f(root) = 0; 若root == NULL 648 * f(root) = f(root->LChild) + f(root->RChild) + 1; 当前root结点为双分支结点 649 * f(root) = f(root->LChild) + f(root->RChild); 其他情况(当前root为单分支结点,或者root为叶子结点) 650 * 王道P.131 第八题 651 * */ 652 int double_son_node(BinaryTree *tree) 653 { 654 if(tree == NULL) 655 return 0; 656 if(tree->LChild != NULL && tree->RChild != NULL) 657 { 658 return double_son_node(tree->LChild) + double_son_node(tree->RChild) + 1; 659 }else 660 { 661 return double_son_node(tree->LChild) + double_son_node(tree->RChild); 662 } 663 } 664 665 /* 666 * 交互二叉树的左右子树(后序遍历的应用) 667 * 1.首先交换root的左孩子的左右子树, 668 * 2.然后交换root的右孩子的左右子树 669 * 3.最后交换root的左右孩子,当结点为空时递归结束 670 * 王道 P.131 第九题 671 * */ 672 void swap_lrchild(BinaryTree *tree) 673 { 674 BinaryTree *tmp; 675 if(tree) 676 { 677 swap_lrchild(tree->LChild); 678 swap_lrchild(tree->RChild); 679 tmp = tree->LChild; 680 tree->LChild = tree->RChild; 681 tree->RChild = tmp; 682 } 683 } 684 /* 685 * 借用队列实现左右子树交换 686 * */ 687 void swap_lrchild2(BinaryTree *root) 688 { 689 BinaryTree *p, *tmp; 690 Tqueue queue; 691 queue.front = queue.rear = 0; 692 if(root) 693 enqueue(&queue, root); 694 while(queue.rear != queue.front) 695 { 696 p = dequeue(&queue); 697 if(p->LChild) 698 enqueue(&queue, p->LChild); 699 if(p->RChild) 700 enqueue(&queue, p->RChild); 701 702 tmp = p->LChild; 703 p->LChild = p->RChild; 704 p->RChild = tmp; 705 } 706 707 } 708 /* 709 * 求先序遍历中的第k个结点的值(确保k值在有效范围内) 710 * 1.设置一个全局变量itag记录访问过的结点的序号,其初值是根结点在先序序列中的序号,即为1 711 * 2.当二叉树tree为空时,返回特殊结点“#”,当itag == k时,表示找到了满足条件的结点,返回 tree->data 712 * 3.当itag != k 是,则递归的在左右子树中继续查找 713 * 王道 P.131 第十题 714 * */ 715 int itag = 1; 716 Telemtype search_k_node(BinaryTree *tree, int k) 717 { 718 if(tree == NULL) 719 return '#'; 720 if(itag == k) 721 return tree->data; 722 itag++; 723 Telemtype ch = search_k_node(tree->LChild, k); 724 if(tree->LChild != NULL) 725 return ch; 726 ch = search_k_node(tree->RChild, k); 727 if(tree->RChild != NULL) //确保一定有返回值 728 return ch; 729 else 730 return '#'; 731 } 732 /* 733 * 层次遍历的基本思想,就是找到 X 结点,然后删除它这棵树 734 * 1.如果当前树根为X结点,直接删掉 735 * 2.否则,进行层次遍历,去找 X,找到了就删掉, 736 * Note:应为之前封装的好,明显要比书上的代码形式统一,也好看的多 737 * 王道 P.132 第十一题 738 * */ 739 void destroy_x_tree(BinaryTree *tree, Telemtype x) 740 { 741 if(tree) 742 { 743 if(tree->data == x) 744 { 745 destory_tree(tree); 746 return; 747 } 748 Tqueue queue; 749 queue.front = queue.rear = 0; 750 enqueue(&queue, tree); 751 while(queue.front != queue.rear) 752 { 753 tree = dequeue(&queue); 754 if(tree->LChild) 755 { 756 if(tree->LChild->data == x) 757 { 758 destory_tree(tree->LChild); 759 tree->LChild = NULL; 760 } else { 761 enqueue(&queue, tree->LChild); 762 } 763 } 764 if(tree->RChild) 765 { 766 if(tree->RChild->data == x) 767 { 768 destory_tree(tree->RChild); 769 tree->RChild = NULL; 770 }else{ 771 enqueue(&queue, tree->RChild); 772 } 773 } 774 } 775 } 776 return; 777 } 778 779 /* 780 * 打印X结点的所有祖先,用到了非递归后序遍历的栈中信息 781 * 1.非递归后序遍历找到X 782 * 2.此时栈中的所有元素均为该结点的祖先结点 783 * Note:树上的代码是后序遍历的不同写法,感觉没必要记那种(应该看一下深入理解后序遍历), 784 * 会一种就够了了,所以我的代码,就是把上边的后序遍历中的输出语句该为了判断是否是当前结点。 785 * 王道 P.133 第十二题 786 * */ 787 788 void print_ancestor_node(BinaryTree *tree, Telemtype x) 789 { 790 Tstack stack; 791 stack.top = -1; 792 if(!tree) 793 printf("the tree is empty!\n"); 794 else{ 795 while(tree || stack.top != -1) { 796 while (tree) { 797 push_stack(&stack, tree); 798 stack.tag[stack.top] = 0; //设置访问标记,0为第一次访问,1为第二次访问 799 tree = tree->LChild; 800 } 801 if (stack.tag[stack.top] == 0) //第一次访问时,转向同层右结点 802 { 803 tree = stack.stroe[stack.top]; //左走到底时,tree是空,必须有这句话 804 stack.tag[stack.top] = 1; 805 tree = tree->RChild; 806 } else { 807 while (stack.tag[stack.top] == 1)//在栈中找到下一个第一次范格纹你的结点,退出循环时并没有pop,所以为其左子结点 808 { 809 tree = pop_stack(&stack); 810 //每次根改动都是下边 811 if(tree->data == x) 812 { 813 814 printf("\n%c ancestor is : \n",tree->data);; 815 for(int i = 0; i <= stack.top; ++i) 816 { 817 printf("%c ", stack.stroe[i]->data); 818 } 819 return; 820 } 821 //********************* 822 } 823 tree = NULL; 824 } 825 } 826 } 827 } 828 /* 829 * 求 p q两个结点的最近公共祖先,非递归后序遍历的应用,就是利用栈信息 830 * 假设p 在 q的左边 831 * 1.后序遍历必然先遍历到 p,这时把栈中的信息借用辅助栈保存起来 832 * 2.继续遍历,遍历到 q 结点的时候,将栈中的结点逐个和辅助栈的结点匹配, 833 * 第一个相等的元素就是p & q的最近公共祖先 834 * 王道 P.134 第13题 835 * */ 836 BinaryTree *nearest_comm_ancestor(BinaryTree *tree, Telemtype p, Telemtype q) 837 { 838 Tstack stack; 839 Tstack ass_stack; 840 stack.top = -1; 841 ass_stack.top = -1; 842 while(tree || stack.top != -1) 843 { 844 while(tree) 845 { 846 push_stack(&stack, tree); 847 stack.tag[stack.top] = 0; 848 tree = tree->LChild; 849 } 850 if(stack.tag[stack.top] == 0) 851 { 852 tree = stack.stroe[stack.top]; 853 stack.tag[stack.top] = 1; 854 tree = tree->RChild; 855 } else { 856 while(stack.tag[stack.top] == 1) 857 { 858 tree = pop_stack(&stack); 859 //每次根改动都是下边 860 if(tree->data == p) 861 { 862 for(int i = 0; i <= stack.top; ++i) 863 { 864 ass_stack.stroe[i] = stack.stroe[i]; 865 ass_stack.top = stack.top; 866 } 867 } 868 if(tree->data == q) 869 { 870 for(int i = stack.top; i >= 0; --i) 871 { 872 for(int j = ass_stack.top; j >= 0; --j) 873 { 874 if(stack.stroe[i]->data == ass_stack.stroe[j]->data) 875 { 876 return stack.stroe[i]; 877 } 878 } 879 } 880 } 881 //********************* 882 } 883 tree = NULL; 884 } 885 } 886 return NULL; 887 } 888 889 /* 890 * 求树的宽度,二叉树的宽度即 某一层拥有最多的结点树(层次遍历的应用) 891 * 将所有节点对应的层次放在一个队列里,然后通过扫描队列求出各层的总结点的个数,最大的层结点即为二叉树的宽度 892 * 王道 P.135 第十四题 893 * */ 894 895 int tree_width(BinaryTree *root) 896 { 897 Tqueue queue; 898 int k, max, i, n; 899 900 if(!root) 901 return 0; 902 903 queue.front = queue.rear = 0; 904 enqueue(&queue, root); 905 queue.level[queue.rear] = 1; 906 907 while(queue.front != queue.rear) 908 { 909 root = dequeue(&queue); 910 k = queue.level[queue.front]; 911 if(root->LChild) 912 { 913 enqueue(&queue, root->LChild); 914 queue.level[queue.rear] = k + 1; 915 } 916 if(root->RChild) 917 { 918 enqueue(&queue, root->RChild); 919 queue.level[queue.rear] = k + 1; 920 } 921 } 922 923 max = 0; i = 0; ///max保存同一层最多的结点个数 924 k = 1; ///k表示从第一层开始查找 925 while(i <= queue.rear) ///i扫描队中所有的元素 926 { 927 n = 0; ///n统计第k层的结点个数 928 while(i <= queue.rear && queue.level[i] == k) 929 { 930 n++; 931 i++; 932 } 933 k = queue.level[i]; 934 if(n > max) 935 max = n; 936 } 937 return max; 938 } 939 940 /* 941 * 15、设有一棵满二叉树(所有结点的值均不相同),已知先序序列,求其后序序列 942 *王道P1 943 * */ 944 945 void pre_to_post(Telemtype pre[], int s1, int e1, Telemtype post[], int s2, int e2) 946 { 947 int half; 948 if(e1 >= s1) 949 { 950 post[e2] = pre[s1]; 951 half = (e1 - s1) / 2; 952 pre_to_post(pre, s1+1, s1+half, post, s2, s2+half-1); 953 pre_to_post(pre, s1+half+1, e1, post, s1+half, e2-1); 954 } 955 } 956 957 /* 958 *16、将二叉树的叶节点按从左到右的顺序连城一个单链表,表头指针为head。 959 * 二叉树按二叉链表的方式存储,链接时用叶结点的右指针域来存放指针单链表 960 * */ 961 962 BinaryTree *head, *pre = NULL; 963 BinaryTree *inorder_List(BinaryTree *root) 964 { 965 if(root) 966 { 967 inorder_List(root->LChild); 968 if (!root->LChild && !root->RChild) { 969 if (!pre) { 970 head = root; 971 pre = root; 972 } else { 973 pre->RChild = root; 974 pre = root; 975 } 976 inorder_List(root->RChild); 977 pre->RChild = NULL; 978 } 979 } 980 return head; 981 } 982 /* 983 * 利用结点的右孩子rchild将一颗二叉树的叶子结点按照从左往右的顺序串成一个单链表 984 * */ 985 void link(BinaryTree *root, BinaryTree *head, BinaryTree *tail) 986 { 987 if(root) 988 { 989 if(!root->LChild && !root->RChild) 990 { 991 if(!head) 992 { 993 head = root; 994 tail = root; 995 }else 996 { 997 tail->RChild = root; 998 tail = root; 999 } 1000 } 1001 link(root->LChild, head, tail); 1002 link(root->RChild, head, tail); 1003 } 1004 } 1005 1006 1007 /* 1008 *17、判断两颗二叉树是否相似 1009 * 相似:T1,T2都是空二叉树或都只有一个根结点,或T1的左子树和T2的左子树相似,T1的右子树和T2的右子树相似 1010 * */ 1011 int is_similar(BinaryTree *T1, BinaryTree *T2) 1012 { 1013 int lvalue, rvalue; 1014 if(!T1 && !T2) 1015 return 1; 1016 else if(!T1 || !T2) 1017 return 0; 1018 else 1019 { 1020 lvalue = is_similar(T1->LChild, T2->LChild); 1021 rvalue = is_similar(T1->RChild, T2->RChild); 1022 return (lvalue&&rvalue); 1023 } 1024 } 1025 1026 /* 1027 *18、写出中序线索二叉树里查找指定结点后序的前驱结点的算法 1028 * */ 1029 1030 /* 1031 *19、求二叉树的带却路径长度(WPL)。 1032 * WPL指二叉树中所有叶结点的带权路径长度之和。 1033 * */ 1034 int wpl_preorder(BinaryTree *root, int deep) 1035 { 1036 static int wpl = 0; 1037 if(!root->LChild && !root->RChild) 1038 wpl += deep*(root->data - '0'); ///此时data中存放的是权值,但我们data是char型。 1039 if(root->LChild) 1040 wpl_preorder(root->LChild, deep+1); 1041 if(root->RChild) 1042 wpl_preorder(root->RChild, deep+1); 1043 return wpl; 1044 } 1045 1046 int WPL(BinaryTree *root) 1047 { 1048 return wpl_preorder(root, 0); 1049 } 1050 1051 /* 1052 int main() 1053 { 1054 BinaryTree *tree; 1055 tree = create_tree(tree); 1056 printf("preorder\n"); 1057 //preorder_traverse(tree); 1058 non_recursion_preorder(tree); 1059 printf("\ninorder\n"); 1060 //inorder_traverse(tree); 1061 non_recursion_inorder(tree); 1062 printf("\npostorder\n"); 1063 //postorder_traverse(tree); 1064 non_recursion_postorder(tree); 1065 printf("\nlevelorder\n"); 1066 levelorder(tree); 1067 printf("\ninvert_levelorder\n"); 1068 invert_levelorder(tree); 1069 printf("\nleft_node`s number is %d\n", sum_leaf(tree)); 1070 printf("\ndepth is %d\n", tree_depth2(tree)); 1071 printf("\ndepth is %d\n", tree_depth(tree)); 1072 //Telemtype A[] = {'A','B','C','D','E','F','G','H','K'}; 1073 //Telemtype B[] = {'B','D','C','A','E','H','G','K','F'}; 1074 Telemtype A[] = {' ', '1', '2', '4', '7', '3', '5', '6', '8'}; 1075 Telemtype B[] = {' ', '4', '7', '2', '1', '5', '3', '8', '6'}; 1076 BinaryTree *root, *root2; 1077 root = pre_in_create_tree(A, B, 1, 8, 1, 8); 1078 puts("\n*********************root traverse\n"); 1079 preorder_traverse(root); 1080 root2 = pre_in_create_tree2(A, B, 1, 8, 1, 8); 1081 puts("\n*********************root2 traverse\n"); 1082 preorder_traverse(root2); 1083 printf("is complete %d\n", is_complete(root)); 1084 printf("double son node is %d\n", double_son_node(root)); 1085 printf("\nthe swap_lrChild2\n"); 1086 swap_lrchild2(tree); 1087 preorder_traverse(tree); 1088 puts("the end swap_LRChile\n"); 1089 preorder_traverse(root2); 1090 printf("\n%c\n", search_k_node(root2, 4)); 1091 destroy_x_tree(root2, '2'); 1092 preorder_traverse(root2); 1093 puts("\nprint_ancestor_node"); 1094 print_ancestor_node(root, '5'); 1095 root2 = nearest_comm_ancestor(root, '5', '6'); 1096 printf("\nthe nearest_comm_ancestor is %c ", root2->data); 1097 printf("\n\nend!!\n\n"); 1098 1099 1100 1101 ///copy_tree Test 1102 BinaryTree *copy_tree_root = copy_tree(tree); 1103 preorder_traverse(copy_tree_root); 1104 preorder_traverse(tree); 1105 ///tree_width Test 1106 int width = tree_width(tree); 1107 printf("\nthe tree`s width is %d\n", width); 1108 1109 ///search_x_level Test 1110 search_x_level(tree, '3'); 1111 search_x_level(tree, '2'); 1112 search_x_level(tree, '1'); 1113 search_x_level(tree, '4'); 1114 1115 ///sum_node 1116 int s_node = sum_node(tree); 1117 printf("%d\n", s_node); 1118 1119 return 0; 1120 } 1121 */ 1122 ///test case :12003400500