树的一般定义
树
- 线性表、表:不适合描述层次结构数据
- 树(tree):是一个非空的有限元素的集合,其中有一个特殊的元素称为根,余下的元素组成树的若干子树
- 递归的思想:每棵树=根+若干棵子树,每棵子树=子树的根+若干棵它的子树
相关术语
- 元素:节点
- 根节点与子树的根节点的关系:边
- 边的两端:父母(parent)&孩子(children)
- 相同父母的节点:兄弟(sibling)
- 叶节点(终端节点):没有孩子的节点
- 根节点(root):没有父亲的节点
- 层(level):根为1,根的孩子为2,……
- 节点的度(degree):孩子的数目
树的种类
- 自由树:根不确定,但可以设定一个根,能够确定其层级结构
- 有根树:节点无顺序
- 有序树:节点是有顺序的,在左边还是右边不一样
森林和有序森林
- 森林(forest):树的集合,通常认为是有根树的集合
- 有序森林(ordered forest):有序树的有序集合
- 有根(有序)树去掉根节点➡️(有序)森林
(有序)森林添加辅节点➡️有根(有序)树
二叉树的定义
二叉树的定义
- 二叉树(binary tree):有限元素集合,或者为空,或者有一个特殊元素根,余下的元素构成2个二叉树(可以为空),即左子树和右子树
二叉树的种类
- 满二叉树:高度为,节点数为
- 完全二叉树:高度为的满二叉树中节点按从上到下,从左到右的顺序从1到进行编号,从中删除编号最后的个节点,编号为,深度为
二叉树的特性
- 二叉树的高度为,,则它至少有个节点,最多有个节点
- 包含n个节点的二叉树的高度,最大为n,最小为
二叉树的描述
公式化描述
- 用一个一维数组当作一个完全二叉树,缺少节点的位置空出来 ➡️浪费空间,且节点的位置之间没有内在约束关系
链表描述
- 树节点:节点类对象,包含数据域、left、right
- n-1条边 ➡️ 2n-(n-1)=n+1个空指针
template<class T>
class BinaryTreeNode {
public:
BinaryTreeNode() {
LeftChild = RightChild = 0;
}
BinaryTreeNode(const T& e) {
data = e;
LeftChild = RightChild = 0;
}
BinaryTreeNode(const T& e, BinaryTreeNode *l, BinaryTreeNode *r){
data = e;
LeftChild = l;
RightChild = r;
}
private:
T data;
//BinaryTreeNode *parent; 方便寻找父节点
BinaryTreeNode *leftchild;
BinaryTreeNode *rightchild;
}
template<class T>
class BinaryTree {
public:
BinaryTree() {
root = 0;}
;
~BinaryTree(){};
bool IsEmpty() const{ //根据是否有根来判断二叉树是否为空
return ((root) ? false : true);
}
bool Root(T& x) const; //返回二叉树的根
void MakeTree(const T& element,
BinaryTree<T>& left, BinaryTree<T>& right);
void BreakTree(T& element, BinaryTree<T>& left,BinaryTree<T>& right);
void PreOrder(void(*Visit)(BinaryTreeNode<T> *u)){ //先序遍历
PreOrder(Visit, root);
}
void InOrder(void(*Visit)(BinaryTreeNode<T> *u)) { //中序遍历
InOrder(Visit, root);
}
void PostOrder(void(*Visit)(BinaryTreeNode<T> *u)) { //后序遍历
PostOrder(Visit, root);
}
void LevelOrder(void(*Visit)(BinaryTreeNode<T> *u)); //层级遍历
private:
BinaryTreeNode<T> *root; //根指针
void PreOrder(void(*Visit)(BinaryTreeNode<T> *u), BinaryTreeNode<T> *t);
void InOrder(void(*Visit)(BinaryTreeNode<T> *u), BinaryTreeNode<T> *t);
void PostOrder(void(*Visit)(BinaryTreeNode<T> *u), BinaryTreeNode<T> *t);
};
template<class T>
bool BinaryTree<T>::Root(T& x) const { //把根节点数据存在x里,如果不存在根节点,返回false
if (root) {
x = root->data;
return true;
}
else
return false;
}
template<class T>
void BinaryTree<T>::MakeTree(const T& element,BinaryTree<T>& left, BinaryTree<T>& right){ //合成二叉树
root = new BinaryTreeNode<T> (element, left.root, right.root);
left.root = right.root = 0;
}
template<class T>
void BinaryTree<T>::BreakTree(T& element,BinaryTree<T>& left, BinaryTree<T>& right){ //分裂二叉树
if (!root) //检查是否为空
throw BadInput();
element = root->data;
left.root = root->LeftChild;
right.root = root->RightChild;
delete root;
root = 0;
}
template <class T>
int BinaryTree<T>::Height(BinaryTreeNode<T> *t) const{ //计算高度的递归函数
if (!t) return 0;
int hl = Height(t->LeftChild);
int hr = Height(t->RightChild);
if (hl > hr)
return ++hl;
else
return ++hr;
}
template <class T>
int BinaryTree<T>::Size(BinaryTreeNode<T> *t) const{ //统计节点数目
if (!t)
return 0;
else
return Size(t->LeftChild)+Size(t- >RightChild)+1;
}
二叉树的遍历
先序、中序、后序遍历(深度优先)
- 按照某种顺序访问树中的每个节点,要求每个节点被访问一次且仅被访问一次
- 遍历顺序(递归)
(1)先序遍历:根节点➡️左子树➡️右子树
(2)中序遍历:左子树➡️根节点➡️右子树
(3)后序遍历:左子树➡️右子树➡️根节点
//先序遍历
template<class T>
void PreOrder(BinaryTreeNode<T> *t){ //二叉树的根节点
if (t) {
Visit(t);
PreOrder(t->LeftChild);
PreOrder(t->RightChild);
}
}
//中序遍历
template <class T>
void InOrder(BinaryTreeNode<T> *t) {
if (t) {
InOrder(t->LeftChild);
Visit(t);
InOrder(t->RightChild);
}
}
//后序遍历
template <class T>
void PostOrder(BinaryTreeNode<T> *t) {
if (t) {
PostOrder(t->LeftChild);
PostOrder(t->RightChild);
Visit(t);
}
}
template <class T>
void Infix(BinaryTreeNode<T> *t) {
if (t) {
cout << '(';
Infix(t->LeftChild);
cout << t->data;
Infix(t->RightChild);
cout << ')';
}
}
逐层遍历(宽度优先)
template<class T>
void LevelOrder(BinaryTreeNode<T> *t){ //二叉树的根节点
LinkedQueue<BinaryTreeNode<T>*> Q; //记录同一层的节点
while(t){
Visit(t);
if(t->LeftChild)
Q.Add(t->LeftChild);
if(t->RightChild)
Q.Add(t->RightChild);
try{
Q.Delete(t); //把队首元素取出来,放到t里面
} catch(OutOfBounds){
return;
}
}
}
由遍历顺序推导二叉树结构
二叉树和森林的互转
- 一般树
(1)父指针表示法:无法寻找
(2)左孩子右兄弟指针表示法 ➡️ 二叉树(一定没有右子树) - 森林转换为二叉树
(1)每棵树单独转换成一棵二叉树
(2)把每棵树接在第一棵树的右子树上
作业6
用循环数组实现双端队列
template<typename T>
class doubleQueue{
public:
doubleQueue<T>& create(int m);
bool isEmpty();
bool isFull();
doubleQueue<T>& addLeft(T t);
doubleQueue<T>& addRight(T t);
T getLeft();
T getRight();
doubleQueue<T>& deleteLeft();
doubleQueue<T>& deleteRight();
void print();
private:
T *dq;
int maxSize;
int capacity;
int left; //最左端元素所在的位置的前一个
int right; //最右端元素所在的位置的后一个
};
template<typename T>
doubleQueue<T>& doubleQueue<T>::create(int m){
maxSize=m;
dq=new T[maxSize];
left=0;
right=0;
capacity=0;
return *this;
}
template<typename T>
bool doubleQueue<T>::isEmpty(){
if(capacity==0)
return true;
else
return false;
}
template<typename T>
bool doubleQueue<T>::isFull(){
if(capacity==maxSize)
return true;
else
return false;
}
template<typename T>
doubleQueue<T>& doubleQueue<T>::addLeft(T t){
if(isFull()){
cout<<"FULL!"<<endl;
return *this;
}
if(left==right)
right=(right+1)%maxSize;
dq[left]=t;
capacity++;
left--;
if(left<0)
left=maxSize-1;
return *this;
}
template<typename T>
doubleQueue<T>& doubleQueue<T>::addRight(T t){
if(isFull()){
cout<<"FULL!"<<endl;
return *this;
}
if(left==right){
left--;
if(left<0)
left=maxSize-1;
}
dq[right]=t;
capacity++;
right=(right+1)%maxSize;
return *this;
}
template<typename T>
T doubleQueue<T>::getLeft(){
return dq[(left+1)%maxSize];
}
template<typename T>
T doubleQueue<T>::getRight(){
int index=right-1;
if(index<0)
index=maxSize-1;
return dq[index];
}
template<typename T>
doubleQueue<T>& doubleQueue<T>::deleteLeft(){
if(isEmpty())
cout<<"WRONG!"<<endl;
left=(left+1)%maxSize;
dq[left]=-1;
capacity--;
return *this;
}
template<typename T>
doubleQueue<T>& doubleQueue<T>::deleteRight(){
if(isEmpty())
cout<<"WRONG!"<<endl;
right--;
if(right<0)
right=maxSize-1;
dq[right]=-1;
capacity--;
return *this;
}
template<typename T>
void doubleQueue<T>::print(){
if(isEmpty()){
cout<<"EMPTY!"<<endl;
return;
}
for(int i=(left+1)%maxSize;i!=right;i=(i+1)%maxSize)
cout<<dq[i]<<" ";
cout<<endl;
}
int main(){
int t;
cout<<"Please input double-queue's max size!"<<endl;
cin>>t;
doubleQueue<int> DQ;
DQ.create(t);
string command;
cout<<"Please input command!"<<endl;
cin>>command;
while(command!="End"){
if(command=="AddLeft"){
cin>>t;
DQ.addLeft(t);
DQ.print();
}
else if(command=="AddRight"){
cin>>t;
DQ.addRight(t);
DQ.print();
}
else if(command=="GetLeft")
DQ.getLeft();
else if(command=="GetRight")
DQ.getRight();
else if(command=="DeleteLeft"){
DQ.deleteLeft();
DQ.print();
}
else if(command=="DeleteRight"){
DQ.deleteRight();
DQ.print();
}
else if(command=="IsEmpty"){
if(DQ.isEmpty())
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
else if(command=="IsFull"){
if(DQ.isFull())
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
cout<<"Please input command!"<<endl;
cin>>command;
}
return 0;
}
构造并输出中缀表达式树
//a+b+c*(d+e)
//缺陷:存储方式不是以完全二叉树形式存储,时间性能较差
void findDelete(string& str){ //删除表达式中的括号
string temp;
for(int i=0;i<str.length();i++){
if(str[i]=='('||str[i]==')'){
temp=str.substr(0,i)+str.substr(i+1,str.length()-i-1);
str=temp;
}
}
}
template<typename T>
class BinaryTree;
template<typename T>
class node{
friend BinaryTree<T>; //声明友元
public:
node(){
parent=leftchild=rightchild=NULL;
}
node(const T& t){
data=t;
parent=leftchild=rightchild=NULL;
}
node(const T& t,node *l,node*r){
data=t;
leftchild=l;
rightchild=r;
leftchild->parent=this;
rightchild->parent=this;
}
T data;
node<T> *parent; //父节点
node<T> *leftchild;
node<T> *rightchild;
};
static int indent; //控制缩进的静态量
template<typename T>
class BinaryTree{
public:
BinaryTree(){
root=NULL;
}
bool isEmpty(){
return ((root==NULL)? true:false);
}
node<T>* getRoot(){ //返回根节点
return root;
}
node<T>* findLast(){ //找到最后一个叶节点并输出
node<T>* t=root;
while(t->rightchild){
t=t->rightchild;
indent++;
}
for(int i=0;i<2*indent;i++)
cout<<" ";
cout<<t->data<<endl;
return t;
}
void combine(const T& t,BinaryTree<T>& left,BinaryTree<T>& right){ //合并树
root=new node<T>(t,left.root,right.root);
left.root=right.root=NULL;
}
void inorder(node<T> *t); //中序遍历输出
BinaryTree<T>& store(string exp); //存储中缀表达式
private:
node<T> *root; //根节点
};
template<typename T>
BinaryTree<T>& BinaryTree<T>::store(string exp){
int i=0;
for(;i<exp.length();i++){ //找到运算符
if(exp[i]=='+'||exp[i]=='-'||exp[i]=='*'||exp[i]=='/')
break;
}
if(i==exp.length()){ //如果运算符两边的表达式只有一个字母
root=new node<T>(exp[0]);
return *this;
}
string tempLeft,tempRight; //把运算符两边分开成两个表达式
tempLeft=exp.substr(0,i);
tempRight=exp.substr(i+1,exp.length()-i-1);
BinaryTree<T> leftTree,rightTree;
combine(exp[i], leftTree.store(tempLeft), rightTree.store(tempRight));
//递归调用store
return *this;
}
template <typename T>
void BinaryTree<T>::inorder(node<T> *t) {
t=t->parent;
for(int i=0;i<2*(indent-1);i++)
cout<<" ";
cout<<t->data<<endl;
for(int i=0;i<2*indent;i++)
cout<<" ";
cout<<t->leftchild->data<<endl;
indent--;
if(t->parent){
inorder(t);
}
}
int main(){
string exp;
cin>>exp;
BinaryTree<char> expression;
findDelete(exp);
expression.store(exp);
expression.inorder(expression.findLast());
return 0;
}
//a+b+c*(d+e)
template<typename T>
class BinaryTree;
template<typename T>
class node{
friend BinaryTree<T>; //声明友元
public:
node(){
leftchild=rightchild=NULL;
}
node(const T& t){
data=t;
leftchild=rightchild=NULL;
}
node(const T& t,node *l,node*r){
data=t;
leftchild=l;
rightchild=r;
}
T data;
node<T> *leftchild;
node<T> *rightchild;
};
template<typename T>
class BinaryTree{
public:
BinaryTree(){
root=NULL;
}
bool isEmpty(){
return ((root==NULL)? true:false);
}
node<T>* getRoot(){ //返回根节点
return root;
}
void inorder(node<T> *t,int begin); //中序遍历输出
void makeTree(stack<node<T>*> &s){ //存入二叉树
node<char> *p=new node<char>(expre.top());
expre.pop();
p->rightchild=s.top();
s.pop();
p->leftchild=s.top();
s.pop();
s.push(p);
root=p;
}
BinaryTree<T>& store(string exp); //存储中缀表达式
private:
stack<char> expre; //储存表达式字符的栈
stack<node<T>*> binaryTreeNode; //储存子树的根节点
node<T> *root; //根节点
};
template<typename T>
BinaryTree<T>& BinaryTree<T>::store(string exp){
for(int i=0;i<exp.length();i++){ //遍历表达式
if(exp[i]=='(') //如果遇到左括号
expre.push(exp[i]); //压栈
else if(exp[i]==')'){ //如果遇到右括号
while(expre.top()!='(') //把两个括号之间的表达式存入二叉树
makeTree(binaryTreeNode);
expre.pop(); //把左括号弹出
}
else if(exp[i]=='+'||exp[i]=='-'){ //如果遇到+ -
if(!expre.empty()){ //当表达式栈不为空
while(expre.top()=='*'||expre.top()=='/') //如果栈顶是* /则先算
makeTree(binaryTreeNode);
}
expre.push(exp[i]); //记得把+ -压栈
}
else if(exp[i]=='*'||exp[i]=='/') //如果遇到* / 优先级最高,直接压栈
expre.push(exp[i]);
else{ //默认除了上述操作符以外就是操作数
node<char> *p=new node<char>(exp[i]);
binaryTreeNode.push(p); //放入子树的根节点栈
}
} //遍历结束
while(expre.top()=='*'||expre.top()=='/') //计算* /
makeTree(binaryTreeNode);
stack<node<T>*> temp;
while(!binaryTreeNode.empty()){ //子树的根节点栈不为空时
temp.push(binaryTreeNode.top()); //入栈
binaryTreeNode.pop();
}
while(expre.size()!=0) //把剩下的表达式字符存入树中
makeTree(temp);
return *this;
}
template <typename T>
void BinaryTree<T>::inorder(node<T> *t,int indent) { //indent用来记录缩进
node<char> *p=t;
if(p){
inorder(p->leftchild,indent+1); //递归输出左子树
cout<<setw(3*indent)<<" "<<p->data<<endl; //输出根
inorder(p->rightchild,indent+1); //递归输出右子树
}
}
int main(){
string exp;
cin>>exp;
BinaryTree<char> expression;
expression.store(exp);
expression.inorder(expression.getRoot(),0);
return 0;
}
二叉树
// 1 2 3 4 5 6 7 8 9 10
// 1 3 2 7 6 5 4 10 9 8
template<typename T>
class BinaryTree;
template<typename T>
class node{
friend BinaryTree<T>; //声明友元
public:
node(){
leftchild=rightchild=NULL;
}
node(const T& t){
data=t;
leftchild=rightchild=NULL;
}
node(const T& t,node *l,node*r){
data=t;
leftchild=l;
rightchild=r;
}
T data;
node<T> *leftchild;
node<T> *rightchild;
};
template<typename T>
class BinaryTree{
public:
BinaryTree(){
root=NULL;
}
bool isEmpty(){
return ((root==NULL)? true:false);
}
node<T>* getRoot(){ //返回根节点
return root;
}
int size(node<T> *t){ //返回节点的数目
if(!t)
return 0;
else
return size(t->leftchild)+size(t->rightchild)+1;
}
void combine(const T& t,BinaryTree<T>& left,BinaryTree<T>& right){ //合并树
root=new node<T>(t,left.root,right.root);
left.root=right.root=NULL;
}
node<T>* store(T *t,int len,int index){ //以完全二叉树的形式存储数据
if(index>=len)
return NULL;
node<T> *temp=new node<T>;
temp->data=t[index];
temp->leftchild=store(t,len,index*2+1); //映射关系
temp->rightchild=store(t,len,index*2+2);
root=temp;
return root;
}
void swap(node<T> *t){ //交换二叉树里所有的左右子树
if(t->leftchild||t->rightchild){ //只要左子树或右子树存在
node<T> *temp=t->leftchild;
t->leftchild=t->rightchild;
t->rightchild=temp;
}
if(t->leftchild)
swap(t->leftchild); //在左子树内部实行交换
if(t->rightchild)
swap(t->rightchild);
}
void levelOrder(node<T> *t){ //以层级遍历输出数据
queue<node<T>*> q; //存储有左右子树的节点
while(t){
cout<<t->data<<" ";
if(t->leftchild)
q.push(t->leftchild); //入队
if(t->rightchild)
q.push(t->rightchild);
if(!q.empty()){
t=q.front();
q.pop(); //出队
}
else //队列为空时退出(仅限于完全二叉树)
break;
}
cout<<endl;
}
int width(node<T> *t){ //返回二叉树的宽度,即同一层最多的叶节点数
queue<node<T>*> q;
int w=0;
while(t){
if(t->leftchild)
q.push(t->leftchild);
if(t->rightchild)
q.push(t->rightchild);
if(q.size()>w)
w=q.size()-1;
if(!q.empty()){
t=q.front();
q.pop();
}
else
break;
}
return w;
}
private:
node<T> *root; //根节点
};
int main(){
BinaryTree<int> b;
int n;
cin>>n;
int *p=new int[n];
for(int i=0;i<n;i++)
cin>>p[i];
b.store(p, n, 0);
b.levelOrder(b.getRoot());
cout<<"There are "<<b.size(b.getRoot())<<" leaf nodes."<<endl;
cout<<"The with of this binary tree is "<<b.width(b.getRoot())<<endl;
b.swap(b.getRoot());
cout<<"Swaped binary tree:"<<endl;
b.levelOrder(b.getRoot());
return 0;
}