最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
二叉搜索树与树的遍历非递归练习
时间:2022-06-25 04:42:14 编辑:袖梨 来源:一聚教程网
复习了二叉搜索树的实现,包括插入、查找和删除操作,顺便做了下二叉树的三种遍历操作。全部操作采用非递归方式。
#include
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 cur=root;
while(cur||!S.empty()) {
while(cur) {
cout<
S.push(cur);
cur=cur->left;
}
if(!S.empty()) {
cur=S.top();S.pop();
cur=cur->right;
}
}
cout< } /* 非递归中序遍历 用栈实现 对于任一结点P, 1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理; 2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子; 3)直到P为NULL并且栈为空则遍历结束 */ void InOrderPrint() const{ if(root==NULL) return; stack 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=cur->right; } } cout< } /* 非递归 后序遍历 用栈实现 要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。 若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。 */ void PostOrderPrint() const { if(root==NULL) return; stack 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< 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; } 相关文章