转载请注明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;
}
}