中序遍历-----二叉查找树的遍历(迭代版,不使用栈或者队列)

二叉查找树(Binary Search Tree)的遍历的方法有很多,通常使用的是递归的遍历,其便于理解,但是使用递归的话会造成程序运行的空间浪费,效率并不高。为此可以使用一个栈来模拟递归的过程,实现迭代版的二叉查找树的遍历。但是会使用到额外的存储空间,虽说在运行效率上比递归版的有所提高,但是额外的存储空间还是一定的浪费。但是如何减少额外的存储空间呢?我们知道二叉查找树是可以转换为一个双向环形链表(二叉查找树与双向环形链表的转化),而链表的遍历是不需要额外的空间的,因此我们可以考虑通过充分利用树的节点的两个指针来优化遍历的过程。

我们都知道在中序遍历的过程中,我们需要用一个栈来存储之前访问过的节点,主要是为了找到当前节点的后继节点,为此我们发现如下图所示的规律。

上图可以看出节点1的后继节点为2,节点2的后继节点为3,节点3的后继节点为4,节点4的后继节点为5,由上述描述可以发现当某个右节点没有右孩子时,其后继节点为其祖父,当其有右孩子时,其后继节点为其右孩子。当某个左节点没有右孩子时,其后继节点为其父亲,反之其后继节点为其右孩子。

从这段寻找后继节点的过程发现,其后继节点的位置与其是否存在右孩子有关,也即与其指向右侧的指针有关,因此我们是否可以使用右指针来指定其后继节点呢?答案是可以的。下图所示为使用右指针指向其后继节点后构成的新的图。

构造上图之后我们再一次遍历二叉查找树时,只需先向左找到第一个不存在左孩子的节点,然后依次打印其key值,打印完之后遍历其右孩子,则其遍历的路径如下图所示

从上图可以看出这样处理之后刚好实现了二叉查找树的中序遍历。下面为代码的具体实现。

构建一颗二叉查找树

node* create(const string& s)
{
	node* res = new node;
	res->left = nullptr;
	res->right = nullptr;
	res->s = s;
	return res;
}
node* insert(node* root, const string& s)
{
	if(root == nullptr)
	{
		root = create(s);
		return root;
	}
	node* temp = root;
	while(temp!=nullptr)
	{
		if(temp->s > s)
		{
			if(temp->left == nullptr)
			{
				temp->left = create(s);
				return root;
			}
			else
				temp = temp->left;
		}
		else
		{
			if(temp->right == nullptr)
			{
				temp->right = create(s);
				return root;
			}
			temp = temp->right;
		}
	}
}

遍历二叉查找树

void in_order_traverse_BST(node* root)
{
	node* cur = root;
	node* pre=nullptr;
	while(cur!=nullptr)
	{
		if(cur->left == nullptr)
		{
			cout<<cur->s<<" ";
			cur = cur->right;
		}
		else
		{
			pre = cur->left;
			while(pre->right != nullptr && pre->right != cur)
				pre = pre->right;
			if(pre->right == nullptr)
			{
				pre->right = cur;
				cur = cur->left;
			}
			else
			{
				cout<<cur->s<<" ";
				pre->right = nullptr;
				cur = cur->right;
			}
		}
	}
}

下面这段代码是创建右链接,以及恢复原来树的形状的代码,若有什么不明白的地方可以画一颗树来具体实现就行。

else
		{
			pre = cur->left;
			while(pre->right != nullptr && pre->right != cur)
				pre = pre->right;
			if(pre->right == nullptr)
			{
				pre->right = cur;
				cur = cur->left;
			}
			else
			{
				cout<<cur->s<<" ";
				pre->right = nullptr;
				cur = cur->right;
			}
		}

测试代码

#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct node
{
	string s;
	node* left;
	node* right;
};
node* insert(node* root, const string& s);
void in_order_traverse_BST(node* root);
void main()
{
	ifstream in("data.txt");
	if(!in.good())
	{
		cout<<"error"<<endl;
		exit(0);
	}
	node* root = nullptr;
	while (!in.eof())
	{
		string s;
		in>>s;
		root = insert(root,s);
	}
	in_order_traverse_BST(root);
}

若有不清楚的地方还请见谅,多多交流

时间: 2024-11-10 01:24:31

中序遍历-----二叉查找树的遍历(迭代版,不使用栈或者队列)的相关文章

java实现线索化二叉树的前序、中序、后续的遍历(完整代码)

java实现线索化二叉树的前序.中序.后续的遍历 比如创建一个二叉树 1 / 3 6 / \ / 8 10 14 线索化二叉树几个概念: n个节点的二叉链表中含有n+1 [公式2n-(n-1)=n+1]个空指针域.利用二叉链表中的空指针域,存放指向该节点在某种遍历次序下的前驱和后继节点的指针(这种附加指针成为线索).如下面的就是6+1=7个空指针域 (8,10,14各有连个指针没有指向 6有一个) 加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树.分为前序线索二叉树.中序线索二叉树.

数据结构之二叉树 (构造 拷贝构造 以及前序中序后续三种遍历方法)

首先二叉树的节点定义如下: struct BinaryNode {                  BinaryNode *_left;                  BinaryNode *_right;                  T _data;                 BinaryNode( T data ) :_data(data), _left( NULL), _right(NULL )                 {}; }; 二叉树的结构以及接口如下 te

二叉树的中序线索化以及遍历

#include <stdio.h> #include <stdlib.h> typedef struct Node { char data; int Ltag; struct Node* LChild; int Rtag; struct Node* RChild; }BitNode, * BiTree; //先序创建二叉树 void CreatBiTree(BiTree* root) { char ch; ch = getchar(); if (ch == '.') *root

!!!树的中序,前序线索化遍历

===== 笔记另写: ====== code: class A{ public: ///inorderMorrisTraversal void inorderMorrisTraversal(TreeNode *root){ TreeNode *curr = root; TreeNode *prev = nullptr; while(curr!=nullptr){ if(curr->left == nullptr){ cout<<curr->val<<" &q

二叉树的前序中序后序遍历相互求法

二叉树的前中后序遍历,他们的递归非递归.还有广度遍历,参见二叉树的前中后序遍历迭代&广度遍历和二叉树的前中后序遍历简单的递归 现在记录已知二叉树的前序中序后序遍历的两个,求另外一个.一般,这两个中一定有中序遍历. 1.已知前序和中序,求后序遍历: 前序:ABDECFG  中序:DBEAFCG 思路简单:前序的第一个节点就是根节点, 中序中找到根节点的位置,根节点之前是其左子树,之后是右子树   按此顺序,依次在左子树部分遍历,右子树部分遍历 C++ 代码: TreeNode *BinaryTre

二叉线索树-创建中序二叉线索树、查找前驱、查找后继、按照前驱或后继遍历

#include <iostream> #include <stack> using namespace std; struct BiThrNode { int data; BiThrNode *left; BiThrNode *right; bool ltag;//0表示left指向左子,1表示left指向直接前驱 bool rtag; //BiThrNode(int val,BiThrNode *l,BiThrNode *r,bool lt,bool rt):data(val)

新手学习算法----二叉树(将一个二叉查找树按照中序遍历转换成双向链表)

题目:将一个二叉查找树按照中序遍历转换成双向链表. 给定一个二叉查找树: 4 / 2 5 / 1 3 返回 1<->2<->3<->4<->5. 思路:如果对于当前节点,把右子树转换成双向链表,然后把左子树转换成双向链表,转换的时候我们都标记了链表的头节点和尾节点,那么只需要将当前节点和左子树的尾部相连,和右子树的头部相连即可. Java代码:这个是借鉴九章里面的解题法.但是对于左右子树转换成二叉树也不是很理解,还待需要继续分析. /** * Definit

编程算法 - 中序遍历 递归/迭代 代码(C)

中序遍历 递归/迭代 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 中序遍历(InOrder)作为二叉搜索树的排序方式, 有着重要的作用. 递归和迭代的方法都需要掌握, 迭代主要使用了栈(stack)进行输入输出. 代码: /* * main.cpp * * Created on: 2014.9.18 * Author: Spike */ /*eclipse cdt, gcc 4.8.1*/ #include <iostream> #inclu

二叉树基本操作续二:前序、中序、后序遍历(非递归 迭代方式)

这里给出二叉树三种遍历方式的迭代实现代码.二叉树的递归实现使用系统栈入栈出栈,而非递归的迭代实现方法就是手动维护一个栈,来模拟递归的入栈出栈过程. 本文没有给出用户栈的代码,如果需要结合上篇的测试代码一起测试,则需要自己实现自己的栈,以及基本的pop.push等栈操作函数. 前序迭代遍历: 1 void iter_preorder(tree_pointer ptr) 2 { 3 //前序遍历:先遍历根节点,然后再分别遍历左右子树 4 int top = -1; 5 tree_pointer st