二叉搜索树与树的遍历非递归练习

复习了二叉搜索树的实现,包括插入、查找和删除操作,顺便做了下二叉树的三种遍历操作。全部操作采用非递归方式。
 

#include<iostream>  

#include<stack>  

using namespace std;  

 

typedef int T;   // 值类型   

 

// 节点定义   

struct node {  

    T val;  

    node *left,*right;  

    node(const T& val):val(val),left(NULL),right(NULL){  

    }  

};  

typedef node* nodePtr;  // 节点指针  

 

// 二叉搜索树实现   

class BST {  

    public:  

        BST(nodePtr r=NULL):root(r){  

        }   

        // 二叉树插入元素   

        void insert(const T& val) {  

            if(root==NULL) {  

                root=new node(val);return;  

            }  

            //cur为当前节点 pre为cur的 前驱节点  

            node *cur=root,*pre;       

            //遍历找到合适的插入位置   

            while(cur) {   

                pre=cur;        // 记录前驱节点   

                cur=cur->val>val?cur->left:cur->right;  // 前进   

            }  

            //根据前驱节点的值 判断插入左还是右   

            if(pre->val>val) pre->left=new node(val);  

            else pre->right=new node(val);    

        }  

        // 二叉树查找元素   

        nodePtr find(const T& val) {  

            nodePtr cur=root;  

            while(cur) {  

                if(cur->val==val) return cur;  

                cur=cur->val>val?cur->left:cur->right;  // 前进   

            }  

            return NULL;  

        }  

        // 删除指定元素   

        void del(const T& val) {  

            //cur为当前节点 pre为cur的 前驱节点  

            nodePtr cur=root,pre;  

            while(cur) {  

                if(cur->val==val) break;  

                pre=cur;  

                cur=cur->val>val?cur->left:cur->right;  // 前进   

            }  

            // 如果未找到节点   

            if(!cur) return;   

              

            // 如果是叶子节点 直接删除即可并改变前驱节点的指向为空   

            if(cur->left==NULL&&cur->right==NULL) {  

                if(cur==root) // 如果刚好是根节点  

                    root=NULL;  

                else if(pre->left==cur) // 左叶子  

                    pre->left=NULL;  

                else // 右叶子   

                    pre->right=NULL;  

                delete cur;  

            }  // 如果是单儿子节点 接删除即可并改变前驱节点的指向为儿子节点   

            else if(cur->left==NULL||cur->right==NULL) {  

                if(cur==root)  // 根节点  

                    root=cur->left==NULL?cur->right:cur->left;  

                else if(pre->left==cur)  // 左儿子   

                    pre->left=cur->left==NULL?cur->right:cur->left;  

                else   // 右儿子   

                    pre->right=cur->left==NULL?cur->right:cur->left;  

                delete cur;  

            } // 双儿子节点  

            else {  

                //找到左儿子中最大值    

                pre=cur;  

                nodePtr p=pre->left;  

                //最大值在最右边   

                while(p->right) {  

                    pre=p;  

                    p=p->right;  

                }   

                cur->val=p->val;  

                if(pre->left==p)   

                    pre->left=NULL;  

                else   

                    pre->right=NULL;  

                delete p;  

            }  

        }  

        /* 非递归前序遍历   用栈实现 

         对于任一结点P: 

         1)访问结点P,并将结点P入栈; 

         2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P; 

         3)直到P为NULL并且栈为空,则遍历结束。 

         */   

        void PreOrderPrint() const{  

            if(root==NULL) return;  

            stack<nodePtr> S;  

            nodePtr cur=root;  

             while(cur||!S.empty()) {  

                while(cur) {  

                    cout<<cur->val<<",";   

                    S.push(cur);  

                    cur=cur->left;  

                 }  

                 if(!S.empty()) {  

                    cur=S.top();S.pop();  

                    cur=cur->right;  

                 }  

             }  

            cout<<endl;  

        }  

        /* 非递归中序遍历   用栈实现 

        对于任一结点P, 

      1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理; 

      2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子; 

      3)直到P为NULL并且栈为空则遍历结束 

         */   

        void InOrderPrint() const{  

            if(root==NULL) return;  

            stack<nodePtr> S;  

            nodePtr cur=root;  

            while(cur||!S.empty()) {   

                while(cur)   

                {  

                    S.push(cur);  

                    cur=cur->left;  

                }  

                if(!S.empty()) {   // 访问当前节点并右子树入栈   

                    cur=S.top();S.pop();  

                    cout<<cur->val<<",";  

                    cur=cur->right;  

                }             

            }  

            cout<<endl;  

        }  

        /* 

        非递归  后序遍历  用栈实现 

        要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。 

        若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。 

        */ 

        void PostOrderPrint() const {  

            if(root==NULL) return;  

            stack<nodePtr> S;  

            nodePtr cur,pre=NULL; //当前节点和前一次访问的节点  

            S.push(root);  

            while(!S.empty()) {  

                cur=S.top();  

                if((cur->left==NULL&&cur->right==NULL)||(pre!=NULL&&(pre==cur->left||pre==cur->right)))  

                {  

                    cout<<cur->val<<",";  //如果当前结点没有孩子结点或者孩子节点都已被访问过   

                    S.pop();  

                    pre=cur;   

                }  

                else 

                {  

                    if(cur->right!=NULL)  

                        S.push(cur->right);  

                    if(cur->left!=NULL)      

                        S.push(cur->left);  

                }  

            }  

        }  

    private :  

        nodePtr root;  // 根节点   

};  

 

int main(int argc, char* argv[])  

{  

    BST bst;  

    bst.insert(12);bst.insert(2);bst.insert(1);bst.insert(122);bst.insert(6);  

    //bst.insert(11);bst.insert(3);bst.insert(66);bst.insert(30);  

    //bst.del(12);  

    bst.InOrderPrint();  

    bst.PreOrderPrint();  

    bst.PostOrderPrint();  

    return 0;  

时间: 2024-09-13 00:08:19

二叉搜索树与树的遍历非递归练习的相关文章

剑指offer系列之二十二:二叉搜索树的后续遍历序列

题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 此题仍然是对二叉树遍历方法的考察,但是与直接对遍历方法的考察不太一样,因为这里的输入是后续遍历的序列,所以要判断该序列是否是某二叉树的后续遍历结果,关键在于找出根节点,根节点的左子树和根节点的右子树,然后继续对左子树和右子树进行判断,直到全部元素访问完毕.这里很显然是一个递归的过程.由于后续遍历是先访问双亲节点,接着访问左孩子,再访问右孩子,所以需

剑指offer系列之二十五:二叉搜索树与双向链表

题目描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 由于二叉搜索树的中序遍历就是排序的,如果是构造单链表,只需要一次中序遍历就可以了,但现在需要构造双链表,也就是在中序遍历的过程中需要设置每个节点的left与right指针,现在问题是如何设置这两个指针?二叉搜索树有一个特点,就是根节点的左子树上所有节点都比根节点的值小,而右子树上的所有节点的值都比根节点的值大,利用这个性质,当遍历根节点的左孩子的时候,可以继续把其当做左子

二叉搜索树的非递归创建和搜索

#include "stdio.h" typedef struct node { int data ; node*lChild ; node*rChild ; }TreeNode ; void Insert(TreeNode**root,int data) //向二叉查找树中插入元素 采用非递归思想 { TreeNode * p=*root ;//获得根结点 TreeNode*q=new TreeNode ;//分配一个要插入的新节点 q->lChild=q->rChild

纸上谈兵: 树, 二叉树, 二叉搜索树[转]

树的特征和定义 树(Tree)是元素的集合.我们先以比较直观的方式介绍树.下面的数据结构是一个树: 树有多个节点(node),用以储存元素.某些节点之间存在一定的关系,用连线表示,连线称为边(edge).边的上端节点称为父节点,下端称为子节点.树像是一个不断分叉的树根. 每个节点可以有多个子节点(children),而该节点是相应子节点的父节点(parent).比如说,3,5是6的子节点,6是3,5的父节点:1,8,7是3的子节点, 3是1,8,7的父节点.树有一个没有父节点的节点,称为根节点(

纸上谈兵: 树, 二叉树, 二叉搜索树

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!   树的特征和定义 树(Tree)是元素的集合.我们先以比较直观的方式介绍树.下面的数据结构是一个树: 树有多个节点(node),用以储存元素.某些节点之间存在一定的关系,用连线表示,连线称为边(edge).边的上端节点称为父节点,下端称为子节点.树像是一个不断分叉的树根. 每个节点可以有多个子节点(children),而该节点是相应子节点的父节点(parent).比如说,3,5

c++-二叉搜索树的遍历问题

问题描述 二叉搜索树的遍历问题 #include<iostream> #include<string> using namespace std; class node{ public: string name; string keyword; node* left; node* right; node(string a = 0, string b = 0, node* c = 0, node* d = 0) : name(a), keyword(b), left(c), right

九度题目1009:二叉搜索树

题目1009:二叉搜索树 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:4308 解决:1919 题目描述: 判断两序列是否为同一二叉搜索树序列 输入: 开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束. 接下去一行是一个序列,序列长度小于10,包含(0~9)的数字,没有重复数字,根据这个序列可以构造出一颗二叉搜索树. 接下去的n行有n个序列,每个序列格式跟第一个序列一样,请判断这两个序列是否能组成同一颗二叉搜索树. 输出: 如果序列相同则输出YES

【算法学习】AVL平衡二叉搜索树原理及各项操作编程实现(C++)

AVLTree即(Adelson-Velskii-Landis Tree),是加了额外条件的二叉搜索树.其平衡条件的建立是为了确保整棵树的深度为O(nLogn).平衡条件是任何节点的左右子树的高度相差不超过1.   在下面的代码中,编程实现了AVL树的建立.查找.插入.删除.遍历等操作.采用C++类封装. AVL树中比较复杂的操作时插入和删除操作.在这里对插入和删除操作进行讲解.   AVL树的插入操作 向AVL树中插入元素可能会导致树失去平衡.但是,我们只需要调整插入点至根节点的路径上不满足平

[华为机试练习题]33.二叉搜索树

题目 描述: 判断两序列是否为同一二叉搜索树序列 题目类别: 树 难度: 中级 运行时间限制: 10Sec 内存限制: 128MByte 阶段: 入职前练习 输入: 开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束. 接下去一行是一个序列,序列长度小于10,包含(0~9)的数字,没有重复数字,根据这个序列可以构造出一颗二叉搜索树. 接下去的n行有n个序列,每个序列格式跟第一个序列一样,请判断这两个序列是否能组成同一颗二叉搜索树. 输出: 如果序列相同则输出YES