本系列算法实现都是在学习数据结构(C++语言版),清华大学邓俊辉教授编,听邓老师edX网课过程中自己实现的例子。
参考链接
主要记录
关键部分, 数据结构的存储, 有四个关键元素
BinNode<T>* m_parent;
BinNode<T>* m_lchild;
BinNode<T>* m_rchild;
T m_data;
具体的BinNode模板类如下
template< typename T >
class BinNode
{
public:
BinNode* m_parent;
BinNode* m_lchild;
BinNode* m_rchild;
T m_data;
unsigned int m_height;
// unsigned int m_deepth;
public:
BinNode(): m_parent(nullptr) , m_lchild(nullptr), m_rchild(nullptr), m_height(0)
{
}
BinNode(const T& data, BinNode* p = nullptr, BinNode* lc = nullptr, BinNode* rc = nullptr)
: m_data(data), m_parent(p) , m_lchild(lc), m_rchild(rc), m_height(0)
{
}
~BinNode() {}
//! judgement bintree
bool isRoot() { return !this->m_parent; }
bool isLchild() { return !isRoot() && this == this->m_parent->m_lchild; }
bool isRchild() { return !isRoot() && this == this->m_parent->m_rchild; }
bool hasParent() { return !isRoot(); }
bool hasLchild() { return this->m_lchild; }
bool hasRchild() { return this->m_rchild; }
bool hasChild() { return hasLchild() || hasRchild(); }
bool hasBothChild() { return hasLchild() && hasRchild(); }
bool isLeaf() { return !hasChild(); }
BinNode* insertLchild(const T& data)
{
if (!hasLchild())
{
m_lchild = new BinNode(data, this);
}
return m_lchild;
}
BinNode* insertRchild(const T& data)
{
if (!hasRchild())
{
m_rchild = new BinNode(data, this);
}
return m_rchild;
}
};
手动建立一个简单的二叉树, 如下图
A(5)
/ \
B(3) C(4)
/ \
D(1) E(2)
/ \
F(9)
代码如下
BinTree bintree;
BinNode*A, *B, *C, *D, *E, *F;
A = bintree.insertRoot(vec.at(0));
B = A->insertLchild(vec.at(1));
C = A->insertRchild(vec.at(2));
D = B->insertLchild(vec.at(3));
E = B->insertRchild(vec.at(4));
F = E->insertRchild(vec.at(5));
//或者
BinTree<int>* bintree;
BinNode<int>*A, *B, *C, *D, *E, *F;
bintree = new BinTree<int>();
A = bintree->insertRoot(5);
B = A->insertLchild(3);
C = A->insertRchild(4);
D = B->insertLchild(1);
E = B->insertRchild(2);
F = E->insertRchild(9);
// do something
delete bintree;
二叉树删除采用后序遍历的思路进行删除, 自下而上, 自左而右.
使用后序递归遍历代码如下
//! remove node and its childs
void removeChildTree(BinNode<T>*node)
{
if (node->hasLchild())
{
removeChildTree(node->m_lchild);
}
if (node->hasRchild())
{
removeChildTree(node->m_rchild);
}
//delete
if (node)
{
std::cout << node->m_data << " ";
fromParentTo(node) = nullptr; //切断来自父节点的指针
delete node;
node = nullptr;
}
}
广度优先搜索算法(Breadth First Search),又叫宽度优先搜索,或横向优先搜索. 在二叉树的遍历中我们也叫层序遍历.
一层一层自上而下, 从左到右的顺序访问节点数据.为了保证先进来的先访问, 也就是先进先出, 使用一个辅助队列queue来实现.
template <typename VST>
void traversalLevel(BinNode*node, VST& visit) //use queue
{
std::queue *> q;
if (node)
{
q.push(node);
}
while (!q.empty())
{
BinNode* tmpNode = q.front();
q.pop();
visit(tmpNode->m_data);
if (tmpNode->hasLchild())
{
q.push(tmpNode->m_lchild);
}
if (tmpNode->hasRchild())
{
q.push(tmpNode->m_rchild);
}
}
}
深度优先搜索遍历二叉树有前中后序三种, 三种遍历的区别如下图,图片来自邓老师书中.
递归的方法非常简单, 代码区别只是visit的位置不一样.
前序遍历顺序如下图,图片来自邓老师书中.
// 深度优先搜索算法(Depth First Search),是搜索算法的一种
template <typename VST>
void traversalPreRecur(BinNode<T>*node, VST& visit)
{
if (node)
{
visit(node->m_data);
if (node->hasLchild())
{
traversalPreRecur(node->m_lchild, visit);
}
if (node->hasRchild())
{
traversalPreRecur(node->m_rchild, visit);
}
}
}
template <typename VST>
void traversalInRecur(BinNode<T>*node, VST& visit)
{
if (node)
{
if (node->hasLchild())
{
traversalInRecur(node->m_lchild, visit);
}
visit(node->m_data);
if (node->hasRchild())
{
traversalInRecur(node->m_rchild, visit);
}
}
}
template VST>
void traversalPostRecur(BinNode<T>*node, VST& visit)
{
if (node)
{
if (node->hasLchild())
{
traversalPostRecur(node->m_lchild, visit);
}
if (node->hasRchild())
{
traversalPostRecur(node->m_rchild, visit);
}
// std::cout << node->m_data << " ";
visit(node->m_data);
}
}
值的一提的是迭代法前中后序遍历是使用一个辅助栈stack来实现的. 尤其注意前序遍历的进栈顺序是先右后左, 因为要保证先访问左边再访问右边.
细节如下
if (tmpNode->hasRchild())
{
s.push(tmpNode->m_rchild);
}
if (tmpNode->hasLchild())
{
s.push(tmpNode->m_lchild);
}
template <typename VST>
void traversalPreIter(BinNode*node, VST& visit)// use stack
{
std::stack *> s;
if (node)
{
s.push(node);
}
while (!s.empty())
{
BinNode* tmpNode = s.top();
s.pop();
visit(tmpNode->m_data);
if (tmpNode->hasRchild())
{
s.push(tmpNode->m_rchild);
}
if (tmpNode->hasLchild())
{
s.push(tmpNode->m_lchild);
}
}
}
template <typename VST>
void traversalInIter(BinNode*node, VST& visit)// use stack
{
std::stack *> s;
while (true)
{
if (node)
{
s.push(node);
node = node->m_lchild;
}
else if (!s.empty())
{
node = s.top();
s.pop();
visit(node->m_data);
node = node->m_rchild;
}
else
return;
}
}
template <typename VST>
void traversalPostIter(BinNode*node, VST& visit)// use stack
{
std::stack *> s;
BinNode* preNodeVisit = nullptr;
while (node) //移动到左子树最下边
{
s.push(node);
node = node->m_lchild;
}
while (!s.empty())
{
node = s.top();
s.pop();
//一个根节点被访问的前提是:无右子树或右子树已被访问过
if (!node->hasRchild() || node->m_rchild == preNodeVisit)
{
visit(node->m_data);
preNodeVisit = node;
}
else// 右子树一定不为空
{
s.push(node);//根节点再次入栈
node = node->m_rchild;
while (node)//移动到右节点左子树最下边
{
s.push(node);
node = node->m_lchild;
}
}
}
}
占坑