二叉树的实现以及分别使用迭代和栈来实现各种遍历的思路

一。什么是二叉树遍历:

   所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题。 
   遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。

二。三种遍历顺序:   

   ① NLR:前序遍历(Preorder Traversal 亦称(先序遍历))
      访问根结点的操作发生在遍历其左右子树之前。
   ② LNR:中序遍历(Inorder Traversal)
      访问根结点的操作发生在遍历其左右子树之中(间)。
   ③ LRN:后序遍历(Postorder Traversal)

      访问根结点的操作发生在遍历其左右子树之后。


三。三种遍历的迭代实现

        public class BinTree {
		public final static int MAX = 40;
		BinTree[] elements = new BinTree[MAX];// 层次遍历时保存各个节点
		int front;// 层次遍历时队首
		int rear;// 层次遍历时队尾
		private Object data; // 数据元数
		private BinTree left, right; // 指向左,右孩子结点的链

		public BinTree() {
		}

		public BinTree(Object data) { // 构造有值结点
			this.data = data;
			left = right = null;
		}

		public BinTree(Object data, BinTree left, BinTree right) { // 构造有值结点
			this.data = data;
			this.left = left;
			this.right = right;
		}

		public String toString() {
			return data.toString();
		}

		// 前序遍历二叉树
		public static void preOrder(BinTree parent) {
			if (parent == null)
				return;
			System.out.print(parent.data + " ");
			preOrder(parent.left);
			preOrder(parent.right);
		}

		// 中序遍历二叉树
		public void inOrder(BinTree parent) {
			if (parent == null)
				return;
			inOrder(parent.left);
			System.out.print(parent.data + " ");
			inOrder(parent.right);
		}

		// 后序遍历二叉树
		public void postOrder(BinTree parent) {
			if (parent == null)
				return;
			postOrder(parent.left);
			postOrder(parent.right);
			System.out.print(parent.data + " ");
		}

		// 层次遍历二叉树 (核心逻辑:front表示打印到哪个下标了-走的慢每次循环一个,rear表示收录到哪个下标了-走的块每次循环可能收录左右两)
		public void LayerOrder(BinTree parent) {
			elements[0] = parent;
			front = 0;
			rear = 1;
			while (front < rear) {
				try {
					if (elements[front].data != null) {
						System.out.print(elements[front].data + " ");
						if (elements[front].left != null)
							elements[rear++] = elements[front].left;
						if (elements[front].right != null)
							elements[rear++] = elements[front].right;
						front++;
					}
				} catch (Exception e) {
					break;
				}
			}
		}

		// 返回树的叶节点个数
		public int leaves() {
			if (this == null)
				return 0;
			if (left == null && right == null)
				return 1;
			return (left == null ? 0 : left.leaves())
					+ (right == null ? 0 : right.leaves());
		}

		// 结果返回树的高度(核心逻辑:左右树取较大者,每次升一级)
		public int height() {
			int heightOfTree;
			if (this == null)
				return -1;
			int leftHeight = (left == null ? 0 : left.height());
			int rightHeight = (right == null ? 0 : right.height());
			heightOfTree = leftHeight < rightHeight ? rightHeight : leftHeight;
			return 1 + heightOfTree;
		}

		// 如果对象不在树中(核心逻辑:先根遍历,找不到的节点都返回-1,知道找到返回1,然后后续均加一级返回)
		public int level(Object object) {
			int levelInTree;
			if (this == null)
				return -1;
			if (object == data)
				return 1;// 规定根节点为第一层
			int leftLevel = (left == null ? -1 : left.level(object));
			int rightLevel = (right == null ? -1 : right.level(object));
			if (leftLevel < 0 && rightLevel < 0)
				return -1;
			levelInTree = leftLevel < rightLevel ? rightLevel : leftLevel;
			return 1 + levelInTree;

		}

		// 将树中的每个节点的孩子对换位置(核心逻辑:从下往上,从左往右依次交换左右节点)
		public void reflect() {
			if (this == null)
				return;
			if (left != null)
				left.reflect();
			if (right != null)
				right.reflect();
			BinTree temp = left;
			left = right;
			right = temp;
		}

		// 将树中的所有节点移走,并输出移走的节点(核心逻辑:中根遍历,先删除没有左右节点的,然后中间,然后右边,从下往上依次删除)
		public void defoliate() {
			if (this == null)
				return;
			// 若本节点是叶节点,则将其移走
			if (left == null && right == null) {
				System.out.print(this + " ");
				data = null;
				return;
			}
			// 移走左子树若其存在
			if (left != null) {
				left.defoliate();
				left = null;
			}
			// 移走本节点,放在中间表示中跟移走...
			String innerNode = this + " ";
			System.out.print(data + " ");
			data = null; 
			// 移走右子树若其存在
			if (right != null) {
				right.defoliate();
				right = null;
			}
		}

		/**
		 * @param args
		 */
		public static void main(String[] args) {
			// TODO Auto-generated method stub
			BinTree e = new BinTree("E");
			BinTree g = new BinTree("G");
			BinTree h = new BinTree("H");
			BinTree i = new BinTree("I");
			BinTree d = new BinTree("D", null, g);

			BinTree f = new BinTree("F", h, i);
			BinTree b = new BinTree("B", d, e);
			BinTree c = new BinTree("C", f, null);
			BinTree tree = new BinTree("A", b, c);

			System.out.println("前序遍历二叉树结果: ");
			tree.preOrder(tree);
			System.out.println();
			System.out.println("中序遍历二叉树结果: ");
			tree.inOrder(tree);
			System.out.println();
			System.out.println("后序遍历二叉树结果: ");
			tree.postOrder(tree);
			System.out.println();
			System.out.println("层次遍历二叉树结果: ");
			tree.LayerOrder(tree);
			System.out.println();
			System.out.println("F所在的层次: " + tree.level("F"));
			System.out.println("这棵二叉树的高度: " + tree.height());
			System.out.println("--------------------------------------");
			tree.reflect();
			System.out.println("交换每个节点的孩子节点后......");
			System.out.println("前序遍历二叉树结果: ");
			tree.preOrder(tree);
			System.out.println();
			System.out.println("中序遍历二叉树结果: ");
			tree.inOrder(tree);
			System.out.println();
			System.out.println("后序遍历二叉树结果: ");
			tree.postOrder(tree);
			System.out.println();
			System.out.println("层次遍历二叉树结果: ");
			tree.LayerOrder(tree);
			System.out.println();
			System.out.println("F所在的层次: " + tree.level("F"));
			System.out.println("这棵二叉树的高度: " + tree.height());
			System.out.println("--------------------------------------");
			tree.defoliate();
		}
	}	
	
	运行结果:
	前序遍历二叉树结果: 
	A B D G E C F H I 
	中序遍历二叉树结果: 
	D G B E A H F I C 
	后序遍历二叉树结果: 
	G D E B H I F C A 
	层次遍历二叉树结果: 
	A B C D E F G H I 
	F所在的层次: 3
	这棵二叉树的高度: 4
	--------------------------------------
	交换每个节点的孩子节点后......
	前序遍历二叉树结果: 
	A C F I H B E D G 
	中序遍历二叉树结果: 
	C I F H A E B G D 
	后序遍历二叉树结果: 
	I H F C E G D B A 
	层次遍历二叉树结果: 
	A C B F E D I H G 
	F所在的层次: 3
	这棵二叉树的高度: 4
	--------------------------------------
	C I F H A E B G D 

四。二叉树的非递归的遍历实现(  B<--A-->C   D<--B-->E   C-->F)

  1.先根遍历

  (先访问根节点,再访问左子树,后访问右子树。而对于每个子树来说,又按照同样的访问顺序进行遍历)
    实现思路如下:
对于任一节点P,
1)输出节点P,然后将其入栈,再看P的左孩子是否为空;
2)若P的左孩子不为空,则置P的左孩子为当前节点,重复1)的操作;
3)若P的左孩子为空,则将栈顶节点出栈,但不输出,并将出栈节点的右孩子置为当前节点,看其是否为空;
4)若不为空,则循环至1)操作;
5)如果为空,则继续出栈,但不输出,同时将出栈节点的右孩子置为当前节点,看其是否为空,重复4)和5)操作;
6)直到当前节点P为NULL并且栈空,遍历结束。

详细分析其先序遍历的非递归实现过程:
  1. 首先,从根节点A开始,根据操作1),输出A,并将其入栈,由于A的左孩子不为空,根据操作2),将B置为当前节点,再根据操作1),将B输出,并将其入栈,           由于B的左孩子也不为空,根据操作2),将D置为当前节点,再根据操作1),输出D,并将其入栈,此时输出序列为ABD;
  2. 由于D的左孩子为空,根据操作3),将栈顶节点D出栈,但不输出,并将其右孩子置为当前节点;
  3. 由于D的右孩子为空,根据操作5),继续将栈顶节点B出栈,但不输出,并将其右孩子置为当前节点;
  4. 由于B的右孩子E不为空,根据操作1),输出E,并将其入栈,此时输出序列为:ABDE;
  5. 由于E的左孩子为空,根据操作3),将栈顶节点E出栈,但不输出,并将其右孩子置为当前节点;
  6. 由于E的右孩子为空,根据操作5),继续将栈顶节点A出栈,但不输出,并将其右孩子置为当前节点;
  7. 由于A的右孩子C不为空,根据操作1),输出C,并将其入栈,此时输出序列为:ABDEC;
  8. 由于A的左孩子F不为空,根据操作2),则将F置为当前节点,再根据操作1),输出F,并将其入栈,此时输出序列为:ABDECF;
  9. 由于F的左孩子为空,根据操作3),将栈顶节点F出栈,但不输出,并将其右孩子置为当前节点;
  10. 由于F的右孩子为空,根据操作5),继续将栈顶元素C出栈,但不输出,并将其右孩子置为当前节点;
  11. 此时栈空,且C的右孩子为NULL,因此遍历结束。
    void pre_traverse(BTree pTree)  
	{  
	    PSTACK stack = create_stack();  //创建一个空栈  
	    BTree node_pop;                 //用来保存出栈节点  
	    BTree pCur = pTree;             //定义用来指向当前访问的节点的指针 
	    
	    while(pCur || !is_empty(stack))  
	    {  
	        //循环遍历根和左孩子
	        printf("%c ", pCur->data);  
	        push_stack(stack,pCur);  
	        pCur = pCur->pLchild;  
	        //到最底部时开始遍历右孩子 
	        while(!pCur && !is_empty(stack))  
	        {  
	            pCur = getTop(stack);  
	            pop_stack(stack,&node_pop);  
	            pCur = pCur->pRchild;              
	        }  
	    }  
     }  

2.中根遍历

 (先访问左子树,再访问根节点,后访问右子树,而对于每个子树来说,又按照同样的访问顺序进行遍历)
    实现思路如下:
对于任一节点P,
1)若P的左孩子不为空,则将P入栈并将P的左孩子置为当前节点,然后再对当前节点进行相同的处理;
2)若P的左孩子为空,则输出P节点,而后将P的右孩子置为当前节点,看其是否为空;
3)若不为空,则重复1)和2)的操作;
4)若为空,则执行出栈操作,输出栈顶节点,并将出栈的节点的右孩子置为当前节点,看起是否为空,重复3)和4)的操作;
5)直到当前节点P为NULL并且栈为空,则遍历结束。

详细分析其中序遍历的非递归实现过程:
  1. 首先,从根节点A开始,A的左孩子不为空,根据操作1)将A入栈,接着将B置为当前节点,B的左孩子也不为空,根据操作1),将B也入栈,接着将D置为当前节           点,由于D的左子树为空,根据操作2),输出D;
  2. 由于D的右孩子也为空,根据操作4),执行出栈操作,将栈顶结点B出栈,并将B置为当前节点,此时输出序列为DB;
  3. 由于B的右孩子不为空,根据操作3),将其右孩子E置为当前节点,由于E的左孩子为空,根据操作1),输出E,此时输出序列为DBE;
  4. 由于E的右孩子为空,根据操作4),执行出栈操作,将栈顶节点A出栈,并将节点A置为当前节点,此时输出序列为DBEA;
  5. 此时栈为空,但当前节点A的右孩子并不为NULL,继续执行,由于A的右孩子不为空,根据操作3),将其右孩子C置为当前节点,由于C的左孩子不为空,根据操           作1),将C入栈,将其左孩子F置为当前节点,由于F的左孩子为空,根据操作2),输出F,此时输出序列为:DBEAF;
  6. 由于F的右孩子也为空,根据操作4),执行出栈操作,将栈顶元素C出栈,并将其置为当前节点,此时的输出序列为:DBEAFC;
  7. 由于C的右孩子为NULL,且此时栈空,根据操作5),遍历结束。
    void in_traverse(BTree pTree)  
	{  
		PSTACK stack = create_stack();  //创建一个空栈  
		BTree node_pop;                 //用来保存出栈节点  
		BTree pCur = pTree;             //定义指向当前访问的节点的指针  
	  
		//直到当前节点pCur为NULL且栈空时,循环结束  
		while(pCur || !is_empty(stack))  
		{  
			if(pCur->pLchild)  
			{  
				//如果pCur的左孩子不为空,则将其入栈,并置其左孩子为当前节点  
				push_stack(stack,pCur);  
				pCur = pCur->pLchild;  
			}  
			else  
			{  
				//如果pCur的左孩子为空,则输出pCur节点,并将其右孩子设为当前节点,看其是否为空  
				printf("%c ", pCur->data);  
				pCur = pCur->pRchild;  
				//如果为空,且栈不空,则将栈顶节点出栈,并输出该节点,  
				//同时将它的右孩子设为当前节点,继续判断,直到当前节点不为空  
				while(!pCur && !is_empty(stack))  
				{  
					pCur = getTop(stack);  
					printf("%c ",pCur->data);      
					pop_stack(stack,&node_pop);  
					pCur = pCur->pRchild;  
				}  
			}  
		}  
	}  

3.后根遍历

(先访问左子树,再访问右子树,后访问根节点,而对于每个子树来说,又按照同样的访问顺序进行遍历)
    实现思路如下:
对于任一节点P,
1)先将节点P入栈;
2)若P不存在左孩子和右孩子,或者P存在左孩子或右孩子,但左右孩子已经被输出,则可以直接输出节点P,并将其出栈,将出栈节点P标记为上一个输出的节点,再将此时的栈顶结点设为当前节点;
3)若不满足2)中的条件,则将P的右孩子和左孩子依次入栈,当前节点重新置为栈顶结点,之后重复操作2);
4)直到栈空,遍历结束。
    
详细分析其后序遍历的非递归实现过程:
  1. 首先,设置两个指针:Cur指针指向当前访问的节点,它一直指向栈顶节点,每次出栈一个节点后,将其重新置为栈顶结点,Pre节点指向上一个访问的节点;
  2. Cur首先指向根节点A,Pre先设为NULL,由于A存在左孩子和右孩子,根据操作3),先将右孩子C入栈,再将左孩子B入栈,Cur改为指向栈顶结点B;
  3. 由于B的也有左孩子和右孩子,根据操作3),将E、D依次入栈,Cur改为指向栈顶结点D;
  4. 由于D没有左孩子,也没有右孩子,根据操作2),直接输出D,并将其出栈,将Pre指向D,Cur指向栈顶结点E,此时输出序列为:D;
  5. 由于E也没有左右孩子,根据操作2),输出E,并将其出栈,将Pre指向E,Cur指向栈顶结点B,此时输出序列为:DE;
  6. 由于B的左右孩子已经被输出,即满足条件Pre==Cur->lchild或Pre==Cur->rchild,根据操作2),输出B,并将其出栈,将Pre指向B,Cur指向栈顶结点C,此时输           出序列为:DEB;
  7. 由于C有左孩子,根据操作3),将其入栈,Cur指向栈顶节点F;
  8. 由于F没有左右孩子,根据操作2),输出F,并将其出栈,将Pre指向F,Cur指向栈顶结点C,此时输出序列为:DEBF;
  9. 由于C的左孩子已经被输出,即满足Pre==Cur->lchild,根据操作2),输出C,并将其出栈,将Pre指向C,Cur指向栈顶结点A,此时输出序列为:DEBFC;
  10. 由于A的左右孩子已经被输出,根据操作2),输出A,并将其出栈,此时输出序列为:DEBFCA;
  11. 此时栈空,遍历结束。
        void beh_traverse(BTree pTree)  
	{  
		PSTACK stack = create_stack();  //创建一个空栈  
		BTree node_pop;          //用来保存出栈的节点  
		BTree pCur;              //定义指针,指向当前节点  
		BTree pPre = NULL;       //定义指针,指向上一各访问的节点  
	  
		//先将树的根节点入栈  
		push_stack(stack,pTree);    
		//直到栈空时,结束循环  
		while(!is_empty(stack))  
		{  
		    //当前节点置为栈顶节点 
			pCur = getTop(stack);   
			
			//如果当前节点没有左右孩子,或者有左孩子或有孩子,但已经被访问输出,  
				//则直接输出该节点,将其出栈,将其设为上一个访问的节点  
			if((pCur->pLchild==NULL && pCur->pRchild==NULL) ||   
				(pPre!=NULL && (pCur->pLchild==pPre || pCur->pRchild==pPre)))  
			{   
				printf("%c ", pCur->data);  
				pop_stack(stack,&node_pop);  
				pPre = pCur;  
			}  
			else  
			{  
				//如果不满足上面两种情况,则将其右孩子左孩子依次入栈  
				if(pCur->pRchild != NULL)  
					push_stack(stack,pCur->pRchild);  
				if(pCur->pLchild != NULL)  
					push_stack(stack,pCur->pLchild);  
			}  
		}  
	}  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
递归方式遍叉树: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right # 先序遍 def preorderTraversal(root: TreeNode) -> List[int]: if not root: return [] res = [] res.append(root.val) res += preorderTraversal(root.left) res += preorderTraversal(root.right) return res # 中序遍 def inorderTraversal(root: TreeNode) -> List[int]: if not root: return [] res = [] res += inorderTraversal(root.left) res.append(root.val) res += inorderTraversal(root.right) return res # 后序遍 def postorderTraversal(root: TreeNode) -> List[int]: if not root: return [] res = [] res += postorderTraversal(root.left) res += postorderTraversal(root.right) res.append(root.val) return res ``` 代方式遍叉树: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right # 先序遍 def preorderTraversal(root: TreeNode) -> List[int]: if not root: return [] res = [] stack = [root] while stack: node = stack.pop() res.append(node.val) if node.right: stack.append(node.right) if node.left: stack.append(node.left) return res # 中序遍 def inorderTraversal(root: TreeNode) -> List[int]: if not root: return [] res = [] stack = [] node = root while stack or node: while node: stack.append(node) node = node.left node = stack.pop() res.append(node.val) node = node.right return res # 后序遍 def postorderTraversal(root: TreeNode) -> List[int]: if not root: return [] res = [] stack = [root] while stack: node = stack.pop() if node.left: stack.append(node.left) if node.right: stack.append(node.right) res.append(node.val) return res[::-1] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值