目录
建立一颗二叉树
二叉树的定义及性质
二叉树的特点是一颗有序树,每个结点的度最大为2。从根结点开始,他的左孩子和右孩子也是一颗树的根结点,也就是这个结点的左子树和右子树
二叉树的分支有左右子树之分,而树的分支无左右子树之分。
两种特殊的二叉树:
满二叉树:深度为h且结点数为2的h次方-1的二叉树,在这种二叉树中,除最后一层全是叶子结点外,其余每一层上的各个结点都有左右孩子。
完全二叉树:深度为h,有n个结点的二叉树,当且仅当每个结点都与深度为h的满二叉树中编号从1到n的结点一一对应。满二叉树是完全二叉树的特殊形式。
完全二叉树具有的特点:
1.所有的叶子节点都在最下面两层,除最后一层外的各层组成的二叉树是一颗满二叉树
2.若某个结点有右孩子,则该结点必有左孩子
性质:
1.二叉树的第i层上的结点个数的最大值为2的i-1次方(i>=1)
2.深度为h的二叉树上的结点个数的最大值为2 的h次方-1,即深度为h的完全二叉树上的结点个数为为2 的h-1次方-1.
3.对任何一颗二叉树,若其终端结点数为n0,度为2的结点数为n2,则n0 = n2 + 1
4.含有n个结点的完全二叉树的深度为[㏒2n]+1
5.具有n个结点的完全二叉树的结点按层次编号(按从上到下。从左到右的方式连续编号),则对任一结点i有:
建立一颗二叉树代码
包括初始化以及销毁
typedef struct Node{
int val;
struct Node *lchild, *rchild;
}Node;
typedef struct tree{
Node *root;
int n;
}Tree;
//初始化结点
Node* GetNewNode(int val){
Node *p = (Node*)malloc(sizeof(Node));
p->val = val;
p->rchild = p->rchild = NULL;
return p;
}
//初始化一个树
Tree*GetNewTree(){
Tree*tree = (Tree*)malloc(sizeof(Tree));
tree->n = 0;
tree->root = NULL;
return tree;
}
Node* insertNode(Node *root, int val){
if(root == NULL)
return GetNewNode(val);
if(root->val == val)
return root;
else if(root->val > val)
root->lchild = insertNode(root->lchild, val);
else
root->rchild = insertNode(root->rchild, val);
return root;
}
//插入一个结点
void insert(Tree*tree, int val){
tree->root = insertNode(tree->root, val);
tree->n++;
return;
}
//销毁
void clearNode(Node* node){
if(node == NULL)
return ;
clearNode(node->lchild);
clearNode(node->rchild);
free(node);
return ;
}
void clearTree(Tree*tree){
clearNode(tree->root);
free(tree);
return;
}
二叉树的遍历
分为前序中序后序遍历,这个前中后都是说的根节点,然后还有层序遍历
先序遍历
先访问根节点,先序遍历左子树,先序遍历右子树
递归方法简单而且好理解,但是对电脑内存栈需求量大
void p1(Node *node){
if(node){
cout << node->val;//先输出跟结点
p1(node->lchild);//遍历左子树
p1(node->rchild);//遍历右子树
}
}
非递归
//先序遍历的非递归算法利用栈的性质
void p_1(Tree *tree){
Node *ro = tree->root;
if(ro){
stack<Node*>s;
s.push(ro);//根节点入栈
while(!s.empty()){
while(s.top() && ro){//栈顶元素非空
cout << s.top()->val;
ro = ro->lchild;
s.push(ro);
}
s.pop();//空结点出栈
if(!s.empty()){
s.pop();
ro = ro->rchild;
s.push(ro);
}
}
}
return ;
}
二叉树遍历就借用了c++STL里面的一部分
中序遍历
void p1(Node *node){
if(node){
p1(node->lchild);//遍历左子树
cout << node->val;//先输出跟结点
p1(node->rchild);//遍历右子树
}
}
中序遍历的非递归几乎和先序一样,会一个就相当于都会了
后序遍历
void p1(Node *node){
if(node){
p1(node->lchild);//遍历左子树
p1(node->rchild);//遍历右子树
cout << node->val;//先输出跟结点
}
}
非递归
//后序遍历的非递归算法利用栈的性质
void p_1(Tree *tree){
Node *ro = tree->root;
if(ro){
stack<Node*>s;
s.push(ro);//根节点入栈
while(!s.empty()){
while(s.top() && ro){//遍历左子树
//cout << s.top()->val;
ro = ro->lchild;
s.push(ro);
}
s.pop();//空结点出栈
if(!s.empty()){//遍历右子树+
cout << a.top()->val;
// s.pop();
// ro = ro->rchild;
// s.push(ro);
if(ro->rchild){
s.push(ro->rchild);//右子树根节点入栈
}
else{//左右子树遍历结束,访问根结点
s.pop();
cout << ro->val;
while(!s.top() && s.top() && ro->rchild == ro){
//若访问的结点是其双亲结点的右孩子,则双亲出栈
s.pop();
cout << ro->val;
}
if(s.empty()){//使栈顶结点的右孩子入栈
s.push(ro->rchild);
}
}
}
}
}
return ;
}
层序遍历
递归方法
void level(Node *node){
Node *p = node;
queue<Node*> q;
q.push(p);
while(!q.empty()){
q.pop();
cout << p->val;
if(p->lchild)
q.push(p->lchild);
if(p->rchild)
q.push(p->rchild);
}
return;
}