二叉排序树——理解与实现

转载请注明t1234xy4 原创:http://blog.csdn.net/t1234xy4/article/details/51570916
二叉树的基本操作:
创建:二叉树的创建就是插入一个节点
查找
深度
遍历
删除节点

下面我们简单的来分析:
一、插入节点
有递归实现与非递归,个人建议用非递归。插入节点的数量很大,树的深度也很大的时候,使用递归可能导致函数调用的递归栈溢出。总的来说,非递归的健壮性要强于递归。

步骤分解:
1、查找插入节点处;
2、插入节点;
先给出递归的实现:

void InsertBST(BinaryTreeNode** root,int key)
{
    if(root == NULL)  return ;
    if(*root == NULL)
    {
        BinaryTreeNode* pNode = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
        if(pNode == NULL) return ;
        pNode->m_Value  = key;
        pNode->m_pLeft = NULL;
        pNode->m_pRight = NULL;
        *root = pNode;
        return ;
    }

    if( key < (*root)->m_Value)
        InsertBST( &((*root)->m_pLeft),key);
    else if(key > (*root)->m_Value)
        InsertBST( &((*root)->m_pRight),key);
    else
        return;
}

步骤1:当root为空的时候,则为root节点;当root不为空时,利用二叉排序树的性质:一个节点的左子树都小于节点值,右子树都大于节点值。直到找为NULL的节点位置
步骤2:在步骤1中,需要使用两个指针,pRootNext用于指向需要插入的位置,pRoot用于指向pRootNext的父节点。然后可以通过生成节点插入到root树中。
插入的非递归实现:

void InsertBinarySortTree(BinaryTreeNode** root,int value)
{
    if(root==NULL) return ;  
    if(*root == NULL)
    {
        BinaryTreeNode* pNode = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
        if(pNode == NULL) return ;
        pNode->m_Value  = value;
        pNode->m_pLeft = NULL;
        pNode->m_pRight = NULL;

        *root = pNode;
        return ;
    }else if(root == NULL || *root == NULL)
        return ;

    BinaryTreeNode* pRoot = *root;
    BinaryTreeNode* pRootNext = NULL;

    if(pRoot->m_Value <value)
        pRootNext = pRoot->m_pRight;
    else if(pRoot->m_Value > value)
        pRootNext = pRoot->m_pLeft;
    else
        return ;

    while(pRootNext!=NULL)
    {
        pRoot = pRootNext;
        if(pRootNext->m_Value > value)
            pRootNext = pRootNext->m_pLeft;
        else if(pRoot->m_Value < value)
            pRootNext = pRootNext->m_pRight;
        else
            return ;
    }

    BinaryTreeNode* pNode = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
    if(pNode == NULL) return ;
    pNode->m_Value  = value;
    pNode->m_pLeft = NULL;
    pNode->m_pRight = NULL;

    if(pRoot->m_Value > value)
        pRoot->m_pLeft = pNode;
    else
        pRoot->m_pRight = pNode;
}

二、遍历
树的遍历使用递归很简单,当前我也没有写非递归的遍历,等下完了继续贴在下面,这里给出递归实现的先序遍历BinaryTreeDLR 和 中序遍历BinaryTreeLDR,通过这两个遍历,可以画出树的结构图,来检验自己的实现是否正确。
代码如下:

void BinaryTreeDLR(BinaryTreeNode* root)
{
    if(root == NULL)    return ;
     printf("%4d",root->m_Value);
     BinaryTreeDLR(root->m_pLeft);
     BinaryTreeDLR(root->m_pRight);
}

void BinaryTreeLDR(BinaryTreeNode* root)
{
    if(root == NULL)    return ;
     BinaryTreeDLR(root->m_pLeft);
     printf("%4d",root->m_Value);
     BinaryTreeDLR(root->m_pRight);
}

三、深度
树的深度计算也很简单,使用递归的方法如下:

/*to be test:
1:完全二叉树
2:满二叉树
3;空树
4:只有根节点的二叉树
*/

int DeepOfBinaryTree(BinaryTreeNode *root)
{
    if(root == NULL)
        return 0;

    int leftdeepth = DeepOfBinaryTree(root->m_pLeft);
    int rightdeepth = DeepOfBinaryTree(root->m_pRight);

    return (leftdeepth>rightdeepth)? (leftdeepth+1) : (rightdeepth+1);
}

非递归的方法等实现了继续更新。

四、收索
利用二叉排序树的特性也十分容易得到代码:
递归与非递归代码如下:

/*to be test:
1: 5 3 2 1 4 9 8 7      4
2: 5 3 2 1 4 9 8 7      6
3: 5 3 2 1 4 9 8 7      9
5: 5                    5
6: null                 4
*/
BinaryTreeNode* SearchBinaryTree(BinaryTreeNode* root,int key)
{
    if(root==NULL)  return NULL;
    if(key < root->m_Value) 
        SearchBinaryTree(root->m_pLeft,key);
    else if(key > root->m_Value)
        SearchBinaryTree(root->m_pRight,key);
    else
        return root;
    return NULL;
}

/*to be test:
1: 5 3 2 1 4 9 8 7      4
2: 5 3 2 1 4 9 8 7      6
3: 5 3 2 1 4 9 8 7      9
5: 5                    5
6: NULL                 4
*/
BinaryTreeNode* SearchBinaryTreeNoRecursion(BinaryTreeNode* root,int key)
{
    if(root == NULL) return NULL;
    BinaryTreeNode* pRoot;
    pRoot = root;
    while(pRoot!=NULL)
    {
        if(key < pRoot->m_Value)
            pRoot->m_pLeft;
        else if(key > pRoot->m_Value)
            pRoot = pRoot->m_pRight;
        else
            return pRoot;

    }
    return NULL;
}

五、删除
二叉排序树节点的删除比较复杂,是所有操作中最难与掌握的部分。步骤分解:
1、查找删除节点
2、判定待删除节点的类型
3、分类型删除节点
删除节点的类型分为:
1. 叶子节点
2. 只有左子树或者右子树的节点
3. 同时有左右子树的节点

三种情况:
叶子节点处理需要考虑:
1. 是根节点,且无叶子节点;
2. 不是根节点;
只有左或右子树的节点;
1. 是根节点,有一叶子节点;
2. 不是根节点;
同时有左右子树的节点:
查找后继节点,将后继节点与当前节点交换;然后转化为1、2情况。

/*to be test:
1: 5 3 2 1 4 9 8 7      4
2: 5 3 2 1 4 9 8 7      6
3: 5 3 2 1 4 9 8 7      9
4: 5 3 2 1 4 9 8 7      3
5: 5 3 2 1 4 9 8 7      1
5: 5                    5
6: 5 6 7 8  7           5
7: NULL                 4
*/
void DeleteKeyOfBinaryTree(BinaryTreeNode** root,int key)
{
    if(root==NULL || ((*root) == NULL) )
        return ;

    BinaryTreeNode* pRoot = *root;
    BinaryTreeNode* pRootNext = pRoot;

    while( pRootNext!=NULL )
    {
        if(key == pRootNext->m_Value)   break;
        pRoot = pRootNext;
        if(key > pRootNext->m_Value)
            pRootNext = pRootNext->m_pRight;
        else 
            pRootNext = pRootNext->m_pLeft;
    }

    if(pRootNext == NULL) return; //no key in Tree

    //convert Node with Two children to Node with one or none 
    if(pRootNext->m_pLeft != NULL && pRootNext->m_pRight != NULL)
    {
        BinaryTreeNode* pPNext = pRootNext;
        BinaryTreeNode* pNext = pRootNext->m_pRight;
        while(pNext->m_pLeft!=NULL)
        {
            pPNext = pNext;
            pNext = pNext->m_pLeft;
        }
        pRootNext->m_Value = pNext->m_Value;
        pRootNext = pNext;
        pRoot = pPNext;
    }

    //delete the node with zero child
    if(pRootNext->m_pLeft == NULL && pRootNext->m_pRight == NULL)
    {
        if(pRootNext == (*root))
            *root = NULL;
        else
            (pRootNext == pRoot->m_pLeft)? (pRoot->m_pLeft = NULL):(pRoot->m_pRight = NULL);
        free(pRootNext);
        return;
    }

    //delete the node with a child
    if(pRootNext->m_pLeft == NULL || pRootNext->m_pRight == NULL)
    {
        if(pRoot == pRootNext) //key is the root value
            (pRootNext->m_pLeft != NULL)?( (*root) = pRootNext->m_pLeft):((*root) = pRootNext->m_pRight);
        else if(pRootNext == pRoot->m_pLeft) //only with the left child
            (pRootNext->m_pLeft != NULL)?(pRoot->m_pLeft = pRootNext->m_pLeft):(pRoot->m_pLeft = pRootNext->m_pRight);
        else //only with the right child
            (pRootNext->m_pLeft != NULL)?(pRoot->m_pRight = pRootNext->m_pLeft):(pRoot->m_pRight = pRootNext->m_pRight);
        free(pRootNext);
        return;
    }
}

源码下载点:http://download.csdn.net/detail/t1234xy4/9539861

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值