二叉树知识总结

本文详细总结了二叉树的非递归后序遍历和层序遍历方法,包括两种非递归后序遍历的实现策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树的定义:
typedef char ElementType;  
  
typedef struct BiTreeNode  
{  
    ElementType data;  
    struct BiTreeNode* lchild;  
    struct BiTreeNode* rchild;  
}BiTreeNode, *BiTree;  

二叉树的创建:

//递归的建立一棵二叉树   
//输入为二叉树的先序序列   
void createBiTree(BiTree &T)  
{  
    char data;  
    data = getchar();  
    if(data == '#')  
    {  
        T = NULL;  
    }  
    else  
    {  
        T = new BiTreeNode;  
        T->data = data;  
        createBiTree(T->lchild);  
        createBiTree(T->rchild);  
    }  
}  


二叉树的递归先序遍历

void preOrder1(BinTree *root)     //递归前序遍历 
{
    if(root!=NULL)
    {
        cout<<root->data<<" ";
        preOrder1(root->lchild);
        preOrder1(root->rchild);
    }
}

二叉树的非递归先序

void preOrder2(BinTree *root)     // 非递归前序遍历 
{
    stack<BinTree*> s;
    BinTree *p=root;
 
    while(p!=NULL||!s.empty())
    {
        while(p!=NULL)
        {
           cout<<p->data<<" ";
            s.push(p);
            p=p->lchild;
        }
 
        if(!s.empty())
        {
            p=s.top();
            s.pop();
            p=p->rchild;
        }
    }
}   //不断向左访问 并输出 然后右边

二叉树的递归中序

void inOrder1(BinTree *root)      //递归中序遍历
{
    if(root!=NULL)
    {
        inOrder1(root->lchild);
        cout<<root->data<<" ";
        inOrder1(root->rchild);
    }
}


非递归中序遍历
void inOrder2(BinTree *root)       // 非递归中序遍历
{
    stack<BinTree*> s;
    BinTree *p=root;
 
    while(p!=NULL||!s.empty())
    {
        while(p!=NULL)
        {
            s.push(p);
            p=p->lchild;
        }
 
        if(!s.empty())
        {
            p=s.top();
            cout<<p->data<<" ";
            s.pop();
            p=p->rchild;
        }
    }    
}

递归后序遍历

void postOrder1(BinTree *root)    //递归后序遍历
{
    if(root!=NULL)
    {
        postOrder1(root->lchild);
        postOrder1(root->rchild);
        cout<<root->data<<" ";
    }    
}

非递归后序遍历(一)

//非递归后序遍历-迭代
void postorderTraversal(TreeNode *root)
{
    stack<TempNode *> s;
    TreeNode *p = root;
    TempNode *temp;
    while(p != NULL || !s.empty())
    {
        while(p != NULL) //沿左子树一直往下搜索,直至出现没有左子树的结点
        {
            TreeNode *tempNode = new TreeNode;
            tempNode->btnode = p;
            tempNode->isFirst = true;
            s.push(tempNode);
            p = p->left;
        }
        if(!s.empty())
        {
            temp = s.top();           
            if(!temp->btnode->right||!temp->isFirst) 
            {              
		s.pop();
		vist(tmp->btnode);
             
            }
            else  //第二次出现在栈顶
            {
             	
		p = temp->btnode->right;
		temp->isFirst ==False
	     }
        }
    }
}

前面三种非递归算法的实质就是用栈来模拟递归,入栈即递归,出栈即回溯。前序和中序都很好理解,关键是后序,后序遍历因为会回溯两次,所以必须新增一个字段 is-first,当第一次访问的时候置为1,第二次访问置为0,这样就可以判断出是否要输出


非递归后序遍历(二)

void postOrder3(BinTree * root)      //非递归后序遍历
{
    stack < BinTree *> s;
    BinTree * cur;                       //当前结点  
    BinTree * pre = NULL;                  //前一次访问的结点  
    s.push(root);
 
     while ( ! s.empty())
    {
        cur = s.top();//拿最上面的
 
//如果当前结点没有孩子结点或者孩子节点都已被访问过 
         if ((cur ->lchild == NULL && cur -> rchild == NULL) ||
           (pre!= NULL && (pre == cur -> lchild || pre == cur -> rchild)))//上一次的是现在的儿子
        {
            cout << cur -> data <<" " ;    
            s.pop();
            pre = cur; 
        }
         else
        {
             if (cur -> rchild != NULL)
                s.push(cur -> rchild);
             if (cur -> lchild != NULL)    
                s.push(cur -> lchild);//先右再左
        }
    }    
}

这一种方法虽然更好理解,但并不是模拟递归过程,它 把入栈顺序是 自己-右边-左边 从上到小没有儿子就输出。

层序遍历

void LevelorderTraversal ( BinTree BT )
{ 
    Queue Q; 
    BinTree T;
 
    if ( !BT ) return; /* 若是空树则直接返回 */
     
    Q = CreatQueue(); /* 创建空队列Q */
    AddQ( Q, BT );
    while ( !IsEmpty(Q) ) {
        T = DeleteQ( Q );
        printf("%d ", T->Data); /* 访问取出队列的结点 */
        if ( T->Left )   AddQ( Q, T->Left );
        if ( T->Right )  AddQ( Q, T->Right );
    }
}

求结点个数

int GetNodeNum(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL) // 递归出口  
        return 0;  
    return GetNodeNum(pRoot->m_pLeft) + GetNodeNum(pRoot->m_pRight) + 1;  
}  
求深度

int GetDepth(BinaryTreeNode * pRoot)  
{  
    if(pRoot == NULL) // 递归出口  
        return 0;  
    int depthLeft = GetDepth(pRoot->m_pLeft);  
    int depthRight = GetDepth(pRoot->m_pRight);  
    return depthLeft > depthRight ? (depthLeft + 1) : (depthRight + 1);   
}  

树的同构

bool StructureCmp(BinaryTreeNode * pRoot1, BinaryTreeNode * pRoot2)  
{  
    if(pRoot1 == NULL && pRoot2 == NULL) // 都为空,返回真  
        return true;  
    else if(pRoot1 == NULL || pRoot2 == NULL) // 有一个为空,一个不为空,返回假  
        return false;  
    bool resultLeft = StructureCmp(pRoot1->m_pLeft, pRoot2->m_pLeft); // 比较对应左子树   
    bool resultRight = StructureCmp(pRoot1->m_pRight, pRoot2->m_pRight); // 比较对应右子树  
    return (resultLeft && resultRight);  
}   

二叉搜索树的插入和删除
BinTree Insert( BinTree BST, ElementType X )
{
    if( !BST ){ /* 若原树为空,生成并返回一个结点的二叉搜索树 */
        BST = (BinTree)malloc(sizeof(struct TNode));
        BST->Data = X;
        BST->Left = BST->Right = NULL;
    }
    else { /* 开始找要插入元素的位置 */
        if( X < BST->Data )
            BST->Left = Insert( BST->Left, X );   /*递归插入左子树*/
        else  if( X > BST->Data )
            BST->Right = Insert( BST->Right, X ); /*递归插入右子树*/
        /* else X已经存在,什么都不做 */
    }
    return BST;
}
 
BinTree Delete( BinTree BST, ElementType X ) 
{ 
    Position Tmp; 
 
    if( !BST ) 
        printf("要删除的元素未找到"); 
    else {
        if( X < BST->Data ) 
            BST->Left = Delete( BST->Left, X );   /* 从左子树递归删除 */
        else if( X > BST->Data ) 
            BST->Right = Delete( BST->Right, X ); /* 从右子树递归删除 */
        else { /* BST就是要删除的结点 */
            /* 如果被删除结点有左右两个子结点 */ 
            if( BST->Left && BST->Right ) {
                /* 从右子树中找最小的元素填充删除结点 */
                Tmp = FindMin( BST->Right );
                BST->Data = Tmp->Data;
                /* 从右子树中删除最小元素 */
                BST->Right = Delete( BST->Right, BST->Data );
            }
            else { /* 被删除结点有一个或无子结点 */
                Tmp = BST; 
                if( !BST->Left )       /* 只有右孩子或无子结点 */
                    BST = BST->Right; 
                else                   /* 只有左孩子 */
                    BST = BST->Left;
                free( Tmp );
            }
        }
    }
    return BST;
}



                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值