二叉查找树(非递归、递归遍历)

二叉查找树:在二叉树的基础上,若左子树不空,则左子树上所有结点的值均小于根结点的值; 若右子树不空,则右子树上所有结点的值均大于根结点的值; 且左、右子树也同时也是 二叉查找树。 亦称二叉排序树、二叉搜索树。

// Binary Search Tree
typedef int keyType;
struct BSNode {
	BSNode(int k) :Key(k), Left(NULL), Right(NULL) {}
	keyType Key;	// 节点值
	BSNode* Left;	// 左子树
	BSNode* Right;	// 右子树
};
class BSTree {	
public:
	bool insert(keyType key);		// 插入
	bool deleted(keyType key);		// 删除
	void PreOrder(BSNode *node);	// 先序遍历
	void InOrder(BSNode* node);		// 中序遍历
	void PosOrder(BSNode* node);	// 后序遍历
	void LevelOrder();	// 层次遍历
	BSTree() :Root(NULL) {}
public:
	BSNode* Root;	// 树根节点
};


插入

// 插入
bool BSTree::insert(keyType key) {
	if (NULL == Root) {
		Root = new BSNode(key);
		return true;
	}
	// 找到待插入节点位置
	BSNode* T = Root;
	Statu flat = UNKNOW;
	while (1) {
		if (key == T->Key) {
			return false;
		}
		else if (key < T->Key) {
			if (NULL == T->Left) {
				flat = LEFT;
				break;
			}
			T = T->Left;
		}
		else {
			if (NULL == T->Right) {
				flat = RIGHT;
				break;
			}
			T = T->Right;
		}
	}
	if (LEFT == flat) {
		T->Left = new BSNode(key);
	}
	else if (RIGHT == flat) {
		T->Right = new BSNode(key);
	}
	return true;
}

删除:

// 前驱、后继:中序遍历下节点的前一个和后一个
// 找某一节点的前驱
keyType FindPre(BSNode* node) { 
	BSNode* T = node->Left;
	while (T->Right) {
		T = T->Right;
	}
	return T->Key;
}
// 找某一节点的后继
keyType FindPos(BSNode* node) { 
	BSNode* T = node->Right;
	while (T->Left) {
		T = T->Left;
	}
	return T->Key;
}
// 删除
bool BSTree::deleted(keyType key) { 
	BSNode* T = Root;
	BSNode* P = T;		// T 的父节点
	// 找到 key 所在节点
	while (T) {
		if (key < T->Key) {
			P = T;
			T = T->Left;
		}
		else if (key > T->Key) {
			P = T;
			T = T->Right;
		}
		else {
			// 叶子节点
			if (NULL == T->Left&&NULL == T->Right) {
				if (P->Left == T) P->Left = NULL;
				else P->Right = NULL;
				return true;
			} 
			// 非叶子节点  找到该节点的 前驱 或 后继
			else if (NULL != T->Right) {	// 有后继
				key = FindPos(T);
				T->Key = key;	// 将 T的后继节点值赋值给 T ,到时候再删后继节点即可
				P = T;
				T = T->Right;
			}
			else if (NULL != T->Left) {		// 无后继再找前驱
				key = FindPre(T);
				T->Key = key;	// 将 T的后继节点值赋值给 T ,到时候再删后继节点即可
				P = T;
				T = T->Left;
			}
		}
	}
	return false;
}

递归遍历:

// 前序遍历
void BSTree::PreOrder(BSNode *node) {
	if (NULL == node) {
		return;
	}
	cout << node->Key << " ";
	PreOrder(node->Left);	
	PreOrder(node->Right);
}
// 中序
void BSTree::InOrder(BSNode* node) {
	if (NULL == node) {
		return;
	}
	InOrder(node->Left);
	cout << node->Key << " ";
	InOrder(node->Right);
}
// 后序
void BSTree::PosOrder(BSNode* node) {
	if (NULL == node) {
		return;
	}
	PosOrder(node->Left);
	PosOrder(node->Right);
	cout << node->Key << " ";
}	
// 层次遍历
void BSTree::LevelOrder() {
	if (NULL == Root) {
		return;
	}
	queue<BSNode*> NODE;
	NODE.push(Root);
	BSNode* T = Root;
	while (!NODE.empty()) {
		T = NODE.front();
		NODE.pop();
		cout << T->Key << " ";
		if (T->Left) NODE.push(T->Left);
		if (T->Right) NODE.push(T->Right);
	}
	cout << endl;
}


非递归遍历

前序:先根 后左 再右

// 前序 (非递归)
void PreOrder(BSTree &Tree) {
	if (NULL == Tree.Root) {
		return;
	}
	stack<BSNode*> NODE;
	NODE.push(Tree.Root);
	BSNode* T = Tree.Root;
	while (!NODE.empty()) {
		T = NODE.top();
		NODE.pop();	    // 会先把左节点的全部出栈 
		cout << T->Key << " ";
		// 先入右节点 再入左节点 
		if (T->Right) NODE.push(T->Right);
		if (T->Left) NODE.push(T->Left);
	}
}

中序:先左 后根 再右

需要先访问最左边的节点(左子树节点持续入栈),再出栈判断是否有右子树,若有右子树,将右子树看成一个小的二叉查找树,同样方法入栈出栈。

// 中序 (非递归)
void InOrder(BSTree &Tree) {
	if (NULL == Tree.Root) {
		return;
	}
	stack<BSNode*> NODE;
	NODE.push(Tree.Root);
	BSNode* T = Tree.Root;
	while (!NODE.empty()) {
		while (T&&T->Left) { 
			if (T->Left) NODE.push(T->Left);
			T = T->Left;
		}
		T = NODE.top();
		NODE.pop();
		cout << T->Key << " ";
		if (T->Right) {    // 该节点有右子树
			NODE.push(T->Right);    
			T = T->Right;  // 做根入栈
		} 
		else {
			T = NULL;      // 防止重复将左孩子入栈
		}
	}
}

后序:先左 后右 再根

// 后序 (非递归)
void PosOrder(BSTree &Tree) {
	if (NULL == Tree.Root) {
		return;
	}
	stack<BSNode*> NODE;
	NODE.push(Tree.Root);
	BSNode* T = Tree.Root;
	BSNode* pT = NULL;		// 记录上一个输出的节点
	while (!NODE.empty()) {
		T = NODE.top();
		if (T->Left == NULL && T->Right == NULL ||			// 叶子处
			(pT != NULL && (pT == T->Left || pT == T->Right))) {	
			// 先遍历左子树 当 pT == T->Right为真时 默认左子树不存在或已遍历
			cout << T->Key << " ";
			NODE.pop();
			pT = T;
		}
		else {
			// 先右后左
			if (T->Right) NODE.push(T->Right);
			if (T->Left) NODE.push(T->Left);
		}
	}
}

小结:非递归遍历需要多熟悉。 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值