二叉树的储存与遍历

来源:互联网 发布:通达信引用周线数据 编辑:程序博客网 时间:2024/06/05 16:48

二叉树的两种储存:顺序储存 链式储存

四种遍历:层次遍历 前序遍历 中序遍历 后序遍历

1.储存

- 顺序储存:
首先用零元素将二叉树填充为完全二叉树,再将填充后的二叉树节点按层次顺序的次序储存到数组中
这里写图片描述
这里写图片描述
存储后即为:
这里写图片描述

由于顺序储存效率低,所以一般不这样进行二叉树的储存。

- 链式储存:

二叉链表的结点结构为

template<class T>struct BTNode{    T data;    BTNode *left *right ;//指向左右孩子的指针    BTNode(const T& item=T(),lptr=NULL,BTNode* rptr=NULL):            data(item),left(lptr),right(rplt){}};

建立二叉链表结点的函数

template<class T>BTNode <T> * GetBTNode(const T& item,BTNode<T> *lp=NULL,BTNode<T> *rp=NULL){    BTNode <T> *p;    p=new BTNode<T> (item,lp,rp);    if(p==NULL)    {        cout<<"Memory allocation failure!"<<endl;        exit(1);    }    return (p);}

图一应用举例:

BTNode<char> *nullp = NULL;BTNode<char> *fp = GetBTNode('F');BTNode<char> *dp = GetBTNode('D', fp);BTNode<char> *bp = GetBTNode('B', nullp, dp);//若直接用NULL,非法,由于无法确定NULL类型BTNode<char> *ep = GetBTNode('E');//合法,左右孩子取,默认值BTNode<char> *cp = GetBTNode('C', nullp, ep);BTNode<char> *ap = GetBTNode('A', bp, cp);

2.遍历

- 层次遍历:
层次遍历顾名思义就是将结点一层一层的进行遍历,如例图中就为ABCDE

非递归层次遍历运用了队列,简单讲一下队列有着先进先出的原则,层次遍历可以出队之后访问,入队之前访问

出队之后访问:

template<class T>void Level(const BTNode<T>* t){    if(t==NUll)    return ;    queue<const BTNode<T>*> Q;    Q.Push(t)//入栈函数,在queue.h内    while(!Q.Empty())    {        t=Q.Pop();//出栈函数,移除第一个数据并赋给t指针        cout<<t->data;        if(t->left)            Q.Push(t->left);        if(t->right)            Q.Push(t->right)    }}

出队之前访问

template<class T>void Level(const BTNode<T>* t){    if(t==NUll)    return ;    queue<const BTNode<T>*> Q;    cout<<t->data;    Q.Push(t)    while(!Q.Empty())    {        t=Q.Pop();        if(t->left)        {            cout<<t->left->data;            Q.Push(t->left);        }           if(t->right)        {            cout<<t->right->data;            Q.Push(t->right);           }           }}

- 前序遍历
前序遍历也称之为深度优先遍历,算法的递归描述为
1.访问根节点
2.前序遍历左子树
3.前序遍历右子树

例图中前序遍历即为ABDFCE,运用了用户栈,用户栈有着先进后出的原则,在前序遍历中栈实质是为了寄存右子树的根指针,将左指针所指的左子树遍历后,再遍历右子树。
代码如下:

template <class T>void SimPreorder(const BTNode <T>* t){    if(!t)        return ;    stack<const BTNode<T>*> S;//用户栈    while(t||!S.Empty())        if(t)        {            cout<<t->data;            if(t->right)                S.push(t->right);//入栈            t=t->left;        }        else                t=S.Pop();//清除栈的最后进入的一位}

关于前序遍历,有些算法和它还是很相近的,比如二分快速排序,集合幂集求解。后期会补上相关博客

- 中序遍历
中序遍历中,也用到栈,其意义是寄存根节点,以便于左子树遍历完成后取出根指针,访问根指针并取出右子树进行遍历,算法的递归描述:
1.中序遍历左子树
2.访问根节点
3.中序遍历右子树
代码如下:

template<class T>void Siminorder(const BTNode<T>* t){    if(!t)        return ;    stack<const BTNode<T>*> S;    while (t||!S.Empty())    {        if(t)        {            S.Push(t);            t=t->left'        }        else        {            t=S.Pop();            cout<<t->data;            t-t->right;        }    }}

- 后序遍历
后序遍历非递归算法任然是栈来实现,但是不同的是后序遍历用了两个栈,一个栈是为了寄存根节点,一个栈是为了记录相应的结点指针入栈的次数,后序遍历结点会进栈两次,第一次遍历左子树,第二次为了遍历右子树

递归算法描述:
1.后序遍历左子树
2.后序遍历右子树
3.访问根节点

代码实现:

template<class T>void SimPostorder(const BTNode<T>* t){    if (!t)        return ;    int tag;    Stack<const BTNode<T>*> S;    Stack<int> tagS;    const BTNode <T>*temp;    while (t || !S.Empty())    {        if (t)        {            S.Push(t);            tagS.Push(1);            t = t->left;        }        else        {            temp = S.Pop();            tag = tagS.Pop();            if (tag == 1)            {                S.Push(temp);                tagS.Push(2);                t = temp->right;            }            else                cout << temp->data;        }    }}

记录的还是有些粗略,后期会再进行详解

注: 片段代码或者语言如有错误望谅解并请指出。

原创粉丝点击