二叉树学习
最近有了大把的时间,学习了数据结构,在大学的时候就接触过数据结构,在现在那时只不过是为了考一个二级证,那时的概念只是背,但是一直不理解解,还好,我打算重走这段历史。
回归正题:
二叉树的概念
二叉树是n(n>=0)个结点的有限集合,该集合或者为空集(成为空二叉树),或者由一个节点和两棵不互相交的,分别称为根节点的左子树和右子树的二叉树组成。
二叉树的特点
- 每个结点最多有两棵子树
- 左右子树是有顺序的,不能颠倒的
- 即使子树只有一个结点,也要区分它是左子树还是右子树。
特殊二叉树
- 斜树
所有的结点都只有左子树的二叉树叫做左斜树。所有结点都只有右子树的二叉树叫做右斜树。这样二叉树的结点数与树的深度有关。
2. 满二叉
在一棵二叉树中,如果所有的分支结点都存在左子树和右子树,并且所有的叶子都在同一层上,这样的二叉树叫做满二叉。在同深度的二叉树中满二叉树的叶子结点个数最多,叶子树最多。
3. 完全二叉树
对一棵树具有n个节点的二叉树按层序编号,如果编号为i(1<=i<=n)的结点与同深度的满二叉树编号为i的节点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。
完全二叉树的特点:
1)叶子结点只能出现在最下两层
2)最下层的叶子一定集中在左部连续位置
3)倒数二层,若有叶子节点,一定都在右部连续位置
4)如果结点度为1,则该节点只有左子树,即不存在只有右子树的情况
5)同样结点数的二叉树,完全二叉树的深度最小。
二叉树的构建
- 两个类的声明:
class BintreeNode { private: int data; BintreeNode *rightChild,*leftChild; public: BintreeNode(const int &item,BintreeNode *right=NULL,BintreeNode *left=NULL):data(item),rightChild(right),leftChild(left){}; void setRightchild(BintreeNode* r) { rightChild=r; } BintreeNode* getRightchild() { return rightChild; } void setLeftchild(BintreeNode* r) { leftChild = r; } BintreeNode * getLeftchild() { return leftChild; } void setData(int data) { data = data; } int getData() { return data; } }; class BinTree{ private: BintreeNode *root; public: BinTree(BintreeNode *Item=NULL):root(Item){}; ~BinTree() { delete root; }; void setRoot(BintreeNode *item) { root = item; } BintreeNode *getRoot() { return root; } BintreeNode *creat_tree(); void pre_order(BintreeNode *Item) const; void in_order(BintreeNode *Item) const; void post_order(BintreeNode *Item) const; void level_order(BintreeNode *Item)const; int get_leaf_num(BintreeNode *Item) const; int get_tree_height(BintreeNode *Item) const; void swap_left_right(BintreeNode *Item) const; //BintreeNode * get_near_common_father(BintreeNode *root,BintreeNode *r,BintreeNode *l) const; void print_rout(BintreeNode *Item,int sun) const; bool is_in_tree(BintreeNode *r,BintreeNode *Item) const; };
2.二叉树的构建
BintreeNode *BinTree::creat_tree() { char item; BintreeNode *t,t_r,t_l; cin>>item; if(item!='#') { BintreeNode *pNode = new BintreeNode(item-48);//由于0的ascii码是48,这样做是为了把字符转化为数字 t = pNode; t_l = creat_tree(); //先构建左子树后构建右子树 t->setLeftchild(t_l); t_r = creat_tree(); t->setRightchild(t_r); return t; } else { t = NULL; return t; } }
二叉树的前序遍历
void BinTree::pre_order(BintreeNode *Item) const { if(Item!=NULL) { cout<<Item->data<<endl; pre_order(Item->leftChild); //先遍历二叉树的左子树->左子树上的右子树->在遍历二叉树的右子树->右子树上的左子树->右子树上的右子树 pre_order(Item->rightChild); } }
二叉树的中序遍历
void BinTree::in_order(BintreeNode *Item) const { if(Item!=NULL) { in_order(Item->leftChild); cout<<Item->data<<endl; in_order(Item->rightChild); } }
二叉树的后续遍历
void BinTree::post_order(BintreeNode *Item) const { if(Item!=NULL) { post_order(Item->leftChild); post_order(Item->rightChild); cout<<Item->data<<endl; } }
得到二叉树的节点总数
int BinTree::get_leaf_num(BintreeNode *Item) const { if (Item == NULL) { return 0; } if(Item->getLeftchild() == NULL && Item->getRightchild() == NULL) { return 1; } return (get_leaf_num(Item->getLeftchild())+get_leaf_num(Item->getRightchild())); }
得到树的深度
int get_tree_height(BintreeNode *Item) const { if (Item == NULL) { return 0; } if(Item->getLeftchild()==NULL && Item->getRightchild() == NULL) { return 1; } int l_tree = get_tree_height(Item->getLeftchild()); int r_tree = get_tree_height(Item->getRightchild()); return l_tree >=r_tree ? l_tree+1 : r_tree+1; }
交互左子树与右子树
void BinTree::swap_left_right(BintreeNode *Item) { if(Item == NULL) { return NULL; } BintreeNode *tmp = Item->getLeftchild(); Item->setLeftchild(Item->getRightchild()); Item->setRightchild(tmp); swap_left_right(Item->getLeftchild()); swap_left_right(Item->getRightchild()); }
节点查看是否在根为r的二叉树中存在Item这个节点。
bool BinTree::is_in_tree(BintreeNode *r,BintreeNode *Item) const { if(!r) { return NULL; } else if(r == Item) { return false; } else { bool has = false; if(r->getLeftchild() != NULL) { has = is_in_tree(r->getLeftchild(),Item); } if(!has && r->getRightchild()!=NULL) { has = is_in_tree(r->getRightchild(),Item) } return has; } }
如何查找二叉树中两个结点最近的双亲结点?稍后讨论