1 二叉 搜索/排序 树
算法 分析 + 伪代码 + 图示 见 如下链接
https://www.jianshu.com/p/f634b2f1839e
// 1.
// BinaryTree.h
#ifndef _BINARYTREE_H
#define _BINARYTREE_H
typedef struct B_tree_node
{
int key;
struct B_tree_node* parent;
struct B_tree_node* lchild;
struct B_tree_node* rchild;
}B_tree_node;
B_tree_node*
create_node(int key);
void
connect_nodes(B_tree_node* _parent,
B_tree_node* _lchild,
B_tree_node* _rchild);
void
destory_tree(B_tree_node* proot);
void
print_node_and_child(B_tree_node* pnode);
void
print_tree(B_tree_node* proot);
#endif
// 2.
// BinaryTree.cpp
#include <cstdio>
#include <stdlib.h> // malloc / free
#include "BinaryTree.h"
B_tree_node*
create_node(int key)
{
B_tree_node* pnode = (B_tree_node*)malloc( sizeof(B_tree_node) );
pnode->key = key;
pnode->parent = NULL;
pnode->lchild = NULL;
pnode->rchild = NULL;
return pnode;
}
void
connect_nodes(B_tree_node* _parent,
B_tree_node* _lchild,
B_tree_node* _rchild)
{
if(_parent != NULL)
{
_parent->lchild = _lchild;
_parent->rchild = _rchild;
}
if(_lchild != NULL)
_lchild->parent = _parent;
if(_rchild != NULL)
_rchild->parent = _parent;
}
void
destory_tree(B_tree_node* proot)
{
if (proot != NULL)
{
B_tree_node* lchild = proot->lchild;
B_tree_node* rchild = proot->rchild;
free(proot);
proot = NULL;
destory_tree(lchild);
destory_tree(rchild);
}
}
void
print_node_and_child(B_tree_node* pnode)
{
if(pnode != NULL)
{
printf("node key: %d\n", pnode->key);
if(pnode->lchild != NULL)
printf("lchild key: %d.\n", pnode->lchild->key);
else
printf("lchild is null.\n");
if(pnode->rchild != NULL)
printf("rchild key: %d.\n", pnode->rchild->key);
else
printf("rchild key is null.\n");
}
else
printf("this node is null.\n");
}
void
print_tree(B_tree_node* proot)
{
print_node_and_child(proot);
if(proot != NULL)
{
if(proot->lchild != NULL)
print_tree(proot->lchild);
if(proot->rchild != NULL)
print_tree(proot->rchild);
}
}
// 3.
// b_tree_client.cpp : Defines the entry point for the console application.
// binary order tree
#include <cstdio>
#include <iostream>
#include <vector>
#include <stack>
#include "BinaryTree.h"
//---1. traverse: preorder / inorder / postorder
// 先 根/序: 根 -> 左 -> 右
// recursion version:
void
preorder_tree_walk(B_tree_node* walk)
{
if (walk != NULL)
{
printf("%d ", walk->key);
preorder_tree_walk(walk->lchild);
preorder_tree_walk(walk->rchild);
}
}
// iteration version:
// 用 栈, 时/空 复杂度 O(N)
std::vector<int>
preorder_tree_walk_iter(B_tree_node* proot)
{
//(1) vector: 存 output sequence
std::vector<int> result_vec;
//(2) stack: 存 即将 遍历的 pnode,
// 后 进 先 出/遍历
std::stack<const B_tree_node*> stk;
//(3) root pointer 先入栈
if (proot != nullptr)
stk.push(proot);
//(4) stack 再循环: 若 栈 not empty
while (!stk.empty())
{
// 1) get/top old_top elem/pnode
// 2) pop top elem
// 3) old_top.key 入 vector
// 4) old_top->rchild 入栈
// 5) old_top->lchild 入栈
const B_tree_node* p = stk.top();
stk.pop();
result_vec.push_back(p->key);
if (p->rchild != nullptr)
stk.push(p->rchild);
if (p->lchild != nullptr)
stk.push(p->lchild);
}
for (std::vector<int>::iterator
iter = result_vec.begin();
iter != result_vec.end();
++iter)
std::cout << *iter << ' ' << std::endl;
return result_vec;
}
// 中序: 左 -> 根 -> 右
// 以 walk 为 root 的 子树
// recursion version:
void
inorder_tree_walk(B_tree_node* walk)
{
if (walk != NULL)
{
inorder_tree_walk(walk->lchild);
printf("%d ", walk->key);
inorder_tree_walk(walk->rchild);
}
}
// iteration version:
std::vector<int>
inorder_tree_walk_iter(B_tree_node* proot)
{
std::vector<int> result_vec;
std::stack<const B_tree_node*> stk;
const B_tree_node* p = proot;
// out:
// case1: stk empty
// case2: p == NULL
while ( !stk.empty() || p != nullptr)
{
//(1) pnode != NULL 时, 沿左孩子 push + 左下
if (p != nullptr)
{
stk.push(p);
p = p->lchild;
}
else //(2) 直到 不能再 左下(pnode == NULL/ old_pnode->lchild == NULL)
{
// 1) get/top old_pnode elem/pnode
p = stk.top();
// 2) old_pnode.key 入 vector
result_vec.push_back(p->key);
// 3) pop old_pnode
stk.pop();
// 4) get old_top->rchild,
// ready to be processd in next iteration
p = p->rchild;
}
}
for (std::vector<int>::iterator
iter = result_vec.begin();
iter != result_vec.end();
++iter)
std::cout << *iter << ' ' << std::endl;
return result_vec;
}
// 后序: 左 -> 右 -> 根
void
postorder_tree_walk(B_tree_node* walk)
{
if (walk != NULL)
{
postorder_tree_walk(walk->lchild);
postorder_tree_walk(walk->rchild);
printf("%d ", walk->key);
}
}
// iteration version:
// 需要 record 刚 访问过 的 node
std::vector<int>
postorder_tree_walk_iter(B_tree_node* proot)
{
std::vector<int> result_vec;
std::stack<const B_tree_node*> s;
const B_tree_node* cur = proot, // current_visiting
*just_visited = nullptr;
// 2 层 循环
do
{
//(1) 以 current 为 root, 沿左孩子 push + 左下,
// 找到 左孩子为空 的 pnode:
// out:
// cur == NULL / old_cur->lchild == NULL
while (cur != nullptr)
{
s.push(cur);
cur = cur->lchild;
}
// (2) 循环处理 old_cur 及其 右子树
// 1) just_visited 必须先 置空
just_visited = nullptr;
while ( !s.empty() )
{
// 2) get/top old_cur
cur = s.top();
// 3) old_cur 先 pop
s.pop();
// 4) 若 old_cur->rchild 刚已访问,
// 则, 下来该 访问 old_cur:
// 1> old_cur->key 入 vector
// 2> just_visited 更新为 old_cur
// case1: cur->rchild == just_visited == NULL
// case2: cur->rchild == just_visited != NULL
if (cur->rchild == just_visited)
{
result_vec.push_back(cur->key);
just_visited = cur;
}
else // 若 old_cur->rchild 刚没访问
{
//1> old_cur 再次 push
s.push(cur);
//2> 先 process 右子树
// cur 更新 为 old_cur->rchild
cur = cur->rchild;
//3> 跳出 内层 循环
break;
}
}
} while (!s.empty());
for (std::vector<int>::iterator
iter = result_vec.begin();
iter != result_vec.end();
++iter)
std::cout << *iter << ' ' << std::endl;
return result_vec;
}
//---2. find: 指定 / 最小 / 最大 node
// 指定 node 的 next / prev
// (1)
B_tree_node*
tree_search(B_tree_node* walk, int key)
{
// until: walk == NIL or walk.key == key(隐含 walk != NIL )
while (walk != NULL && walk->key != key)
{
if (key < walk->key)
walk = walk->lchild;
else
walk = walk->rchild;
}
return walk;
}
//(2)
B_tree_node*
tree_minimum(B_tree_node* walk)
{
// out: walk == NULL or walk->lchild == NULL(隐含 walk != NULL)
while (walk != NULL && walk->lchild != NULL)
walk = walk->lchild;
return walk;
}
//(3) 与 tree_minimum 对称
B_tree_node*
tree_maximum(B_tree_node* walk)
{
while (walk != NULL && walk->rchild != NULL)
walk = walk->rchild;
return walk;
}
// (4)
B_tree_node*
tree_successor(B_tree_node* walk)
{
if (walk == NULL)
return walk;
// below 初始 必 walk != NIL
// walk 有 右孩子 -> 后继 为 右孩子 最小值
if (walk->rchild != NULL)
return tree_minimum(walk->rchild);
// below 初始 必 walk != NIL, walk.rchild == NIL
// 取 walk.p -> 据 walk 是 root / lchild / rchild 分别处理
B_tree_node* walk_p = walk->parent;
// walk 一直 左上(walk 为 rchild 才能满足 能左上 的 条件),
// until walk 无法左上
// while exit:
// case1: walk_p == NULL => walk == root
// case2: walk_p != NULL && walk == walk_p.lchild
// note: while 每次迭代 前后 必 walk != NIL
while (walk_p != NULL && walk == walk_p->rchild)
{
walk = walk_p; //== walk.p => walk 往 左上走
walk_p = walk_p->parent; //== walk.p => walk_p 联动为 walk.p, 也往 左上走
}
return walk_p;
}
// (5) 与 tree_successor 对称
B_tree_node*
tree_predecessor(B_tree_node* walk)
{
if (walk == NULL)
return walk;
if (walk->lchild != NULL)
return tree_maximum(walk->lchild);
B_tree_node* walk_p = walk->parent;
while (walk_p != NULL && walk == walk_p->lchild)
{
walk = walk_p;
walk_p = walk_p->parent;
}
return walk_p;
}
//---3. insert / delete
// 可能改变 根指针 => 将 根指针 的 指针 传进来
void
tree_insert(B_tree_node** proot, B_tree_node* z)
{
B_tree_node* walk_p = NULL;
B_tree_node* walk = *proot;
// loop out: walk == NIL
// if while execute >= 1 time // Tree not empty
// => after every iteration,
// walk_p/walk_old != NIL
// else execute == 0 time // Tree empty
// => walk == *proot == NIL, walk_p = NIL
while (walk != NULL)
{
walk_p = walk;
if(z->key < walk->key)
walk = walk->lchild;
else // >=
walk = walk->rchild;
}
// below: firstly walk == NIL
// link z <-> z.parent / walk_p / y
z->parent = walk_p;
if (walk_p == NULL)
*proot = z; // 改变 根指针
else if (z->key < walk_p->key) // below: walk_p != NIL
walk_p->lchild = z;
else
walk_p->rchild = z;
}
// 可能改变 根指针 => 将 根指针 的 指针 传进来
void
transplant(B_tree_node** proot,
B_tree_node* u,
B_tree_node* v)
{
if (u == *proot && u == NULL)
*proot = v;
if (u->parent == NULL) // u == *proot
*proot = v;
else if (u == u->parent->lchild) // below: firstly u.p != NIL
u->parent->lchild = v;
else // if u == u.p.rchild
u->parent->rchild = v;
if (v != NULL)
v->parent = u->parent;
}
void
tree_delete(B_tree_node** proot, B_tree_node* z)
{
if (z->lchild == NULL) // below: firstly z.lchild != NIL // 可 z.rchild == NIL
transplant(proot, z, z->rchild);
else if (z->rchild == NULL) // z.lchild != NIL && z.rchild == NIL
transplant(proot, z, z->lchild);
else // z.lchild != NIL && z.rchild != NIL
{
B_tree_node* y = tree_minimum(z->rchild); // z_next / y
if( y->parent != z )
{
//(1)
transplant(proot, y, y->rchild);
//(2) link y <-> z.rchild
y->rchild = z->rchild;
y->rchild->parent = y;
}
//(3)
transplant(proot, z, y);
//(4) link y<-> z.lchild
y->lchild = z->lchild;
y->lchild->parent = y;
}
}
//---4. depth
// 用 queue, 时/空 复杂度 O(N)
std::vector<int>
BFS_tree_walk(B_tree_node* proot)
{
//(1) vector: 存 output sequence
std::vector<int> result_vec;
//(2) queue: 存 即将 遍历的 pnode,
// 后 进 先 出/遍历
std::queue<const B_tree_node*> que;
//(3) root pointer 先入栈
if (proot != nullptr)
que.push(proot);
//(4) stack 再循环: 若 栈 not empty
while (!que.empty())
{
// 1) get/top old_top elem/pnode
// 2) pop top elem
// 3) old_top.key 入 vector
// 4) old_top->lchild 入 queue
// 5) old_top->rchild 入 queue
const B_tree_node* p = que.front();
que.pop();
result_vec.push_back(p->key);
if (p->lchild != nullptr)
que.push(p->lchild);
if (p->rchild != nullptr)
que.push(p->rchild);
}
for (std::vector<int>::iterator
iter = result_vec.begin();
iter != result_vec.end();
++iter)
std::cout << *iter << ' ' << std::endl;
return result_vec;
}
int tree_depth(B_tree_node* proot)
{
if(proot == NULL)
return 0;
int ldepth = tree_depth(proot->lchild);
int rdepth = tree_depth(proot->rchild);
return (ldepth > rdepth) ? (ldepth + 1) : (rdepth + 1);
}
// ====================test cases:====================
void
Test(B_tree_node** pnode, B_tree_node* z)
{
// ---1. walk
// inorder_tree_walk(pnode);
// preorder_tree_walk_iter(pnode);
// inorder_tree_walk_iter(pnode);
// postorder_tree_walk_iter(pnode);
//--- 2. find
/*
B_tree_node* result = tree_search(pnode, 5);
if (result)
printf("found");
else
printf("not found");
*/
/*
B_tree_node* result = tree_maximum(pnode);
// B_tree_node* result = tree_minimum(pnode);
if (result)
printf("found: %d", result->key );
else
printf("not found");
*/
/*
B_tree_node* result = tree_predecessor(pnode);
//B_tree_node* result = tree_successor(pnode);
if (result)
printf("found successor: %d", result->key);
else
printf("not found successor:");
*/
//--- 3. insert / delete
//B_tree_node* pnode_new = create_node(8);
//tree_insert(pnode, pnode_new);
tree_delete(pnode, z);
//--- 4. depth
printf("\n");
}
void
Test_tree_depth(B_tree_node* proot,
int expected_result)
{
int result = tree_depth(proot);
if(expected_result == result)
printf("Test passed.\n");
else
printf("Test failed.\n");
}
// 5
// / \
// 2 6
// /\ \
// 1 4 7
// /
// 3
void Test1()
{
printf("Test1 begins.\n");
B_tree_node* pnode1 = create_node(5);
B_tree_node* pnode2 = create_node(2);
B_tree_node* pnode3 = create_node(6);
B_tree_node* pnode4 = create_node(1);
B_tree_node* pnode5 = create_node(4);
B_tree_node* pnode6 = create_node(7);
B_tree_node* pnode7 = create_node(3);
connect_nodes(pnode1, pnode2, pnode3);
connect_nodes(pnode2, pnode4, pnode5);
connect_nodes(pnode3, NULL, pnode6);
connect_nodes(pnode5, pnode7, NULL);
//Test(pnode5);
//Test(pnode7);
Test(&pnode1, pnode2);
print_tree(pnode1);
destory_tree(pnode1);
}
// 5
// /
// 4
// /
// 3
// /
// 2
// /
// 1
void Test2_left_list()
{
printf("Test2_left_list begins.\n");
B_tree_node* pnode1 = create_node(5);
B_tree_node* pnode2 = create_node(4);
B_tree_node* pnode3 = create_node(3);
B_tree_node* pnode4 = create_node(2);
B_tree_node* pnode5 = create_node(1);
connect_nodes(pnode1, pnode2, NULL);
connect_nodes(pnode2, pnode3, NULL);
connect_nodes(pnode3, pnode4, NULL);
connect_nodes(pnode4, pnode5, NULL);
Test(&pnode1, pnode3);
print_tree(pnode1);
destory_tree(pnode1);
}
// 1
// \
// 2
// \
// 3
// \
// 4
// \
// 5
void Test3_right_list()
{
printf("Test3_right_list begins.\n");
B_tree_node* pnode1 = create_node(1);
B_tree_node* pnode2 = create_node(2);
B_tree_node* pnode3 = create_node(3);
B_tree_node* pnode4 = create_node(4);
B_tree_node* pnode5 = create_node(5);
connect_nodes(pnode1, NULL, pnode2);
connect_nodes(pnode2, NULL, pnode3);
connect_nodes(pnode3, NULL, pnode4);
connect_nodes(pnode4, NULL, pnode5);
Test(&pnode1, pnode3);
print_tree(pnode1);
destory_tree(pnode1);
}
void Test4_only_one_node()
{
printf("Test4_only_one_node begins.\n");
B_tree_node* pnode1 = create_node(1);
Test(&pnode1, pnode1);
print_tree(pnode1);
destory_tree(pnode1);
}
void Test5_empty_tree()
{
printf("Test5_empty_tree begins.\n");
//Test(NULL);
}
int main()
{
Test1();
Test2_left_list();
Test3_right_list();
Test4_only_one_node();
//Test5_empty_tree();
return 0;
}
2 遍历 迭代版
morris 遍历:
原理: 利用 leaf node 左右孩子为 nullptr, 来 压缩空间
`将 迭代版二叉树遍历`
空间复杂度 从 O(N) 降为 O(1)
时间复杂度 O(N)
`待后续研究`