1.二叉树知识点复习
二叉树是不存在度大于2的结点的树,且结点的子树有左右之分
⑴主要性质:
①二叉树的第i层最多有2^(i-1)个结点。
②一颗深度为k的二叉树最多有2^k-1个结点。
③设一颗二叉树的结点数为n,其中度为0,1,2的结点分别为n0,n1,n2,则有n0=n2+1.
(树枝数=n-1=n1+2*n2)
④具有n的结点的完全二叉树,其深度k为logn取下整+1。
⑵满二叉树:一颗k层的具有最多结点数的二叉树。
⑶完全二叉树:一颗k层的二叉树,其中前k-1层是满二叉树,最后一层的结点从左向右依次排列的树。
⑷二叉链表:一种包含三个域的结构体组成的链表,其中包含指向左子树的结点、数据域、指向右子树的结点。另外,一颗具有n的结点的二叉链表,有n+1个空链域 (树枝数=非空链域数=n-1)
⑸线索二叉树:将二叉树的空链域利用起来,存储二叉树在某种遍历次序下,该结点的前驱结点和后继结点的指针。所以,按照遍历方法,线索二叉树可分为前序、中序、后序线索二叉树。
线索二叉树的结点结构是:lchild+ltag+data+rtag+rchild
tag标记为0时,表示两个链域指向孩子
tag标记为1时,对于lchild,指向前驱结点;对于rchild,指向后继结点。
2.二叉树的建立和遍历代码
建立用前序遍历的方法输入二叉树的各个结点值,对于空结点可以指定一个字符来代表,我用的是数字0.
遍历主要有前中后序遍历和层次遍历。
前中后序遍历包含了递归和非递归方法,层次遍历使用队列。
⑴结点结构和二叉树类
struct Node
{
int data;
Node *lchild;
Node *rchild;
};
class BiTree
{
private:
Node* root;
public:
BiTree();
Node* getRoot();
Node* buildTree();
void visit(Node* t);
void pre_traverse_recursion(Node *pos);
void pre_traverse_non_recursion();
void in_traverse_recursion(Node *pos);
void in_traverse_non_recursion();
void post_traverse_recursion(Node *pos);
void post_traverse_non_recursion();
void level_traverse_queue();
};
⑵二叉树的建立
BiTree::BiTree()
{
root = buildTree();
}
Node* BiTree::buildTree()
{
Node *cur;
int data;
cin >> data;
if (data==0)
{
cur= NULL;
}
else
{
cur = new Node; //这里要不放在一开始就new 否则会有异常
cur->data = data;
cur->lchild = buildTree();
cur->rchild = buildTree();
}
return cur;
}
⑶前序遍历
void BiTree::visit(Node* t)
{
cout << t->data << " ";
}
void BiTree::pre_traverse_recursion(Node *pos)
{
if (pos)
{
visit(pos);
pre_traverse_recursion(pos->lchild);
pre_traverse_recursion(pos->rchild);
}
}
void BiTree::pre_traverse_non_recursion()
{
/*
①访问节点数据 ②结点入栈 ③访问左子树,重复①②③直至当前结点左子树为空
④弹出栈顶结点,其右子树作为当前结点,回到①
*/
stack<Node*> s;
s.push(root);
Node*pos = root;
while (!s.empty())
{
while (pos)
{
visit(pos);
pos = pos->lchild;
if(pos)
s.push(pos);
}
pos = s.top();
s.pop();
pos = pos->rchild;
if (pos)
s.push(pos);
}
}
⑷中序遍历
void BiTree::in_traverse_recursion(Node *pos)
{
if (pos)
{
in_traverse_recursion(pos->lchild);
visit(pos);
in_traverse_recursion(pos->rchild);
}
}
void BiTree::in_traverse_non_recursion()
{
/*
①将当前结点入栈 ②访问当前结点的左子树,重复①②直至当前结点左子树为空
③弹出栈顶结点为当前结点,访问结点数据 ④访问当前结点右子树,回到①
*/
Node* pos = root;
stack<Node*> s;
s.push(root);
while (!s.empty())
{
while (pos)
{
pos = pos->lchild;
if(pos)
s.push(pos);
}
pos = s.top();
s.pop();
visit(pos);
pos = pos->rchild;
if (pos)
s.push(pos);
}
}
⑸后序遍历
void BiTree::post_traverse_recursion(Node *pos)
{
if (pos)
{
in_traverse_recursion(pos->lchild);
in_traverse_recursion(pos->rchild);
visit(pos);
}
}
void BiTree::post_traverse_non_recursion()
{
/*
双栈法:
①根节点入栈1
②当栈1非空时,进行以下操作:弹出栈1顶点压入栈2->当前顶点左子树若非空入栈1->当前结点右子树若非空入栈1
③依次弹出栈2结点并访问
*/
Node* pos = root;
stack<Node*> s1, s2;
s1.push(pos);
while (!s1.empty())
{
pos = s1.top();
s1.pop();
s2.push(pos);
if (pos->lchild)
s1.push(pos->lchild);
if (pos->rchild)
s1.push(pos->rchild);
}
while (!s2.empty())
{
pos = s2.top();
s2.pop();
visit(pos);
}
}
⑹层次遍历
void BiTree::level_traverse_queue()
{
/*
队列
①根节点入队
②当队列非空时:访问队首结点并出队->结点的左子树(若非空)入队->结点的右子树(若非空)入队
*/
queue<Node*> q;
Node* pos = root;
q.push(pos);
while (!q.empty())
{
pos = q.front();
q.pop();
visit(pos);
if (pos->lchild)
q.push(pos->lchild);
if (pos->rchild)
q.push(pos->rchild);
}
}
⑺测试
int main()
{
cout << "请按前序遍历的方式输入二叉树,空结点用0表示:" << endl;
BiTree myTree;
cout << "前序遍历(递归)";
myTree.pre_traverse_recursion(myTree.getRoot());
cout << endl;
cout << "前序遍历(非递归)";
myTree.pre_traverse_non_recursion();
cout << endl;
cout << "中序遍历(递归)";
myTree.in_traverse_recursion(myTree.getRoot());
cout << endl;
cout << "中序遍历(非递归)";
myTree.in_traverse_non_recursion();
cout << endl;
cout << "后序遍历(递归)";
myTree.post_traverse_recursion(myTree.getRoot());
cout << endl;
cout << "后序遍历(非递归)";
myTree.post_traverse_non_recursion();
cout << endl;
cout << "层次遍历";
myTree.level_traverse_queue();
cout << endl;
return 0;
}