二叉树的知识前后学习过几遍,学习过后过段时间总是会遗忘,记录下这次的学习内容,权当做笔记了。也欢迎大家批评指正,共同进步。
树节点定义:
struct treenode
{
int data;
treenode *lchild;
treenode *rchild;
};
指向树的结构:
struct tree
{
treenode *root;
};
一、树的建立
树的建立用的是插入结点的算法:将待插入的结点表示为tempptr,将这个结点值从树根开始向下进行比较:若大于一个比较结点tempptr1则转向比较的右子女,否则转向左子女,直到比较的结点tempptr1为空。在比较的过程中需要一个辅助指针pretempptr1,作为比较结点tempptr1的父结点。最后将tempptr作为pretempptr1的子女,当然还要判断是做左子女还是做右子女。
void maketree(treenode *&root)
{
int temp;
treenode *pretempptr1,*tempptr1;
cout<<"please input a number:\n";
cin>>temp;
if(temp==-1) //若输入-1表示结束树的输入
{
root=NULL;
return;
}
treenode *tempptr=new treenode;
tempptr->data=temp;
tempptr->lchild=NULL;
tempptr->rchild=NULL;
root=tempptr;
cout<<"please input a number:\n";
cin>>temp;
while(temp!=-1)
{
pretempptr1=root;
tempptr1=root;
tempptr=new treenode;
tempptr->data=temp;
tempptr->lchild=NULL;
tempptr->rchild=NULL;
while(tempptr1!=NULL)
{
pretempptr1=tempptr1;
if(tempptr1->data>tempptr->data)
tempptr1=tempptr1->lchild;
else
tempptr1=tempptr1->rchild;
}
if(pretempptr1->data>tempptr->data)
{
pretempptr1->lchild=tempptr;
}
else
pretempptr1->rchild=tempptr;
cout<<"please input a number:\n";
cin>>temp;
}
}
二、广度优先算法
广度优先算法,采用自上而下,从左到右的顺序来遍历。遍历借助队列来实现,实现的要点为:每访问一个结点,若此结点的左子女非空,则将此左子女加入队列;若右子女非空,则将此右子女加入队列。通过这种方式即可保证每一层的结点自左到右依次加入队列。
void breadfirst(treenode *&root)
{
queue<treenode *> queue_tree;
treenode *temp=root;
if(root==NULL)
{
cout<<"the tree is empty!"<<endl;
return;
}
queue_tree.push(temp);
while(!queue_tree.empty())
{
temp=queue_tree.front();
queue_tree.pop();
cout<<temp->data<<" ";
if(temp->lchild!=NULL)
queue_tree.push(temp->lchild);
if(temp->rchild!=NULL)
queue_tree.push(temp->rchild);
}
}
三、树的非递归遍历
前序:
void iterativeNLR(treenode *&root)
{
stack<treenode *> stack_tree;
treenode *temp;
if(root==NULL)
{
cout<<"the tree is empty!"<<endl;
return;
}
temp=root;
//stack_tree.push(root);
while(temp!=NULL||!stack_tree.empty())
{
while(temp!=NULL)
{
cout<<temp->data<<" ";
stack_tree.push(temp);
temp=temp->lchild;
}
if(!stack_tree.empty())
{
temp=stack_tree.top();
stack_tree.pop();
temp=temp->rchild;
}
}
}
中序:
void iterativeLNR( treenode *&root)
{
stack<treenode *> stack_tree;
treenode *temp;
if(root==NULL)
{
cout<<"the tree is empty!"<<endl;
return;
}
temp=root;
//stack_tree.push(temp);
while(!stack_tree.empty()||temp!=NULL)
{
while(temp!=NULL)
{
stack_tree.push(temp);
temp=temp->lchild;
}
if(!stack_tree.empty())
{
temp=stack_tree.top();
cout<<temp->data<<" ";
stack_tree.pop();
// if(temp->rchild!=NULL)
temp=temp->rchild;
}
}
}
后序:
后序稍微复杂一些,因为在访问完一个左子女后待访问该结点的父结点时,需要判断该父结点的右子女是否已经访问:可以借助于一个bool型变量来实现。当bool=true时表示右子女已经访问。
void iterativeLRN(treenode *&root)
{
stack<pair<treenode *,bool>> stack_tree;
treenode *temp=root;
if(root==NULL)
{
cout<<"the tree is empty!"<<endl;
return;
}
while(temp!=NULL||!stack_tree.empty())
{
while(temp!=NULL)
{
stack_tree.push(make_pair(temp,false));
temp=temp->lchild;
}
if(!stack_tree.empty()&&stack_tree.top().second==true)
{
cout<<stack_tree.top().first->data<<" ";
stack_tree.pop();
}
if(!stack_tree.empty())
{
stack_tree.top().second=true;
temp=stack_tree.top().first->rchild;
}
}
}
2018.12.30 上述后序非递归方法保存所有的节点状态,耗费内存,可以进行优化:遍历到当前节点时,只保留下当前节点的遍历状态即可。代码如下:
vector<int> postOrder(TreeNode *root)
{
vector<int> res;
if(root == NULL) return res;
TreeNode *p = root;
stack<TreeNode *> sta;
TreeNode *last = root;
sta.push(p);
while (!sta.empty())
{
p = sta.top();
if( (p->left == NULL && p->right == NULL) || (p->right == NULL && last == p->left) || (last == p->right) )
{
res.push_back(p->val);
last = p;
sta.pop();
}
else
{
if(p->right)
sta.push(p->right);
if(p->left)
sta.push(p->left);
}
}
return res;
}