바이너리 트리의 자바 구현 데이터 구조 (3 개) : 단서 바이너리 트리

바이너리 트리의 데이터 구조 (3) : 단서 바이너리 트리

기본 소개 :
Threaded BinaryTree :
n 개의 노드가있는 이진 연결 목록에는 n + 1 [공식 2n- (n-1) = n + 1] 널 포인터 필드가 포함됩니다. 널 포인터와 이진 연결 목록을 사용하여 특정 순회 순서로 노드의 선행 노드와 후속 노드에 대한 포인터를 저장합니다 (이 추가 포인터는 "단서"가 됨). 단서가있는
이러한 종류의 이진 연결 목록을 단서라고합니다. 연결된 목록, 해당 이진 트리가 단서 이진 트리가됩니다. 단서의 다른 특성에 따라 단서 바이너리 트리는 세 가지 유형으로 나눌 수 있습니다 : 프리 큐 바이너리 트리, 미들 오더 큐 바이너리 트리 및 포스트 큐 바이너리 트리.

노드의 이전 노드를 선행 노드라고합니다. 노드의
다음 노드는 후속 노드가됩니다.
공식적인 설명은 너무 간단합니다. 아래 그림을 참조하십시오.
여기에 사진 설명 삽입
의 그림 에서 이것이 완전한 이진 트리임을 알 수 있지만, 리프 노드 8, 10, 14 및 6의 경우 왼쪽 및 오른쪽 노드가 존재하지 않습니다 (6에는 왼쪽 노드 만 있음). 즉, 사용되지 않은 노드에 포인터가 있습니다.
소위 단서 바이너리 트리는 사용하지 않는 포인터를 사용하여 각 노드가 자신의 전면 및 후면 노드를 가리킬 수 있도록하는 것입니다.
그리고 왜 사전 주문 단서 바이너리 트리, 중간 주문 단서 바이너리 트리 및 후 주문 단서 바이너리 트리로 나뉩니까? 세 가지 상황은 어떻습니까? 이것은 단서의 이진 트리를 순회 할 때 단서의 포인터가 다른 순회 방법으로 인해 다른 지점을 가리 키기 때문입니다.

그래도 이해되지 않으면 다음 그래픽 설명을 참조하십시오.


여기에 사진 설명 삽입
단서 전 바이너리 트리 : 순회 순회 결과는 [8,3,10,1,14,6], 순회 순회 결과 바이너리 트리를 디큐
한 결과는 다음과 같습니다.
여기에 사진 설명 삽입
위 그림에서 알 수 있듯이
8 노드 순회 순회 시간이 우선이므로 선행 노드가 존재하지 않고 후속 노드가 3입니다. 따라서 자유 포인터를 사용하여 후속 노드가 3을 가리 키도록합니다.
10 노드 순차 순회는 3 위이고 왼쪽 및 오른쪽 노드 포인터는 유휴 상태이므로 왼쪽 노드는 이전 노드 3을 가리키고 오른쪽 노드는 후속 노드 1을 가리킬 수 있습니다.
마찬가지로 14 노드 왼쪽 및 오른쪽 포인터는 위와 동일합니다.

문제 분석 :
위의 그림과 텍스트에서 모든 사람은 단서 이진 트리를 명확하게 이해하고 있어야합니다.
그러나 스레드 된 이진 트리를 빌드하기 위해 이러한 방식으로 코드를 구현하면 몇 가지 어려움이 있습니다. ·
바이너리 트리가 스레드 될 때 노드 노드의 왼쪽과 오른쪽은 다음과 같습니다.
왼쪽은 왼쪽 하위 트리를 가리 키거나 이전 노드를 가리킬 수 있습니다. 예를 들어, 그림에서 노드 1의 왼쪽 하위 트리는 왼쪽 하위 트리를 가리키고 노드 10은 이전 노드를 가리 킵니다.
맞아요.
따라서 이것은 코드 구현에 어느 정도의 어려움을 제공합니다.

참조 코드는 다음과 같습니다.


public class ThreadedBinaryTreeDemo {
    
    
	public static void main(String[] args) {
    
    
		BinaryTree threadBinaryTree=new BinaryTree();
		HeroNode root=new HeroNode("孙悟空");
		HeroNode node1=new HeroNode("猪八戒");
		HeroNode node2=new HeroNode("唐三藏");
		HeroNode node3=new HeroNode("沙和尚");
		HeroNode node4=new HeroNode("牛魔王");
		HeroNode node5=new HeroNode("红孩儿");
		HeroNode node6=new HeroNode("白骨精");
		threadBinaryTree.setRoot(root);
		root.setLeftNode(node1);
		root.setRightNode(node2);
		node1.setLeftNode(node3);
		node1.setRightNode(node4);
		node2.setLeftNode(node5);
		node2.setRightNode(node6);
		
		threadBinaryTree.threadNodes(); 
		threadBinaryTree.threadshow();
	}
}

class BinaryTree{
    
    
	HeroNode root;
	//指向前驱节点的指针
	//在递归进行线索化时,pre总是保留前一个节点
	HeroNode pre=null;
	public void setRoot(HeroNode root) {
    
    
		this.root=root;
	}
	//重载threadNodes方法,使node首先为root
	public void  threadNodes() {
    
    
		threadNodes(root);
	}
	//线索化二叉树的方法(中序遍历方式)
	public void threadNodes(HeroNode node) {
    
    
		//先判断node是否为空,为空则不再线索化
		if(node==null) {
    
    
			return;
		}
		//先线索化左子树
		threadNodes(node.getLeftNode());
		//线索化当前节点
		//先处理前驱节点
		if(node.leftNode==null) {
    
    
			//让当前节点额左指针指向前驱节点
			node.setLeftNode(pre);
			//设置当前节点的type为1
			node.setLeftType(1);
		}
		//再处理后继节点
		if(pre!=null&&pre.getRightNode()==null) {
    
    
			//让前驱节点的右指针指向当前节点
			pre.setRightNode(node);
			//修改前驱节点的type为1
			pre.setRightType(1);
		}
		//每处理一个节点后,让当前节点时下一个节点的前驱节点
		pre=node;
		
		
		//再线索化右子树
		threadNodes(node.getRightNode());
	}
	
	//循环遍历线索化二叉树(中序遍历顺序)
	public void threadshow() {
    
    
		//定义一个变量,存储当前遍历的节点,从root开始
		 HeroNode node=root;
		 while(node!=null) {
    
    
			 while(node.getLeftType()==0) {
    
    
				 node=node.getLeftNode();
			 }
			 
			 System.out.println(node.value);
			 
			 while(node.getRightType()==1) {
    
    
				 node=node.getRightNode();
				 System.out.println(node.value);
			 }
			 node=node.getRightNode();
		 }
	}
	
	
	public void frontShow() {
    
    
		if(this.root!=null) {
    
    
			this.root.frontShow();
		}else {
    
    
			System.out.println("二叉树为空,无法遍历");
		}
	}
	public void middleShow() {
    
    
		if(this.root!=null) {
    
    
			this.root.middleShow();
		}else {
    
    
			System.out.println("二叉树为空,无法遍历");
		}
	}
	public void endShow() {
    
    
		if(this.root!=null) {
    
    
			this.root.endShow();
		}else {
    
    
			System.out.println("二叉树为空,无法遍历");
		}
	}
	public void deleteNode(String value) {
    
    
		if(this.root!=null) {
    
    
			if(this.root.value.equals(value)) {
    
    
				this.root=null;
			}else {
    
    
				root.deleteNode(value);
			}
		}else {
    
     
			System.out.println("空树,无法删除");
		}
	}
}

class HeroNode{
    
    
	HeroNode leftNode;
	HeroNode rightNode;
	String value;
	
	//两个参数解决左右子树和前后节点的的混乱问题
	//如果leftType或rightType==0,表示指向的是左右子树,如果等于1,表示指向的是前后节点
	private int leftType;
	private int rightType;
	
	
	public HeroNode(String value) {
    
    
		this.value=value;
	}
	
	
	public int getLeftType() {
    
    
		return leftType;
	}


	public void setLeftType(int leftType) {
    
    
		this.leftType = leftType;
	}


	public int getRightType() {
    
    
		return rightType;
	}


	public void setRightType(int rightType) {
    
    
		this.rightType = rightType;
	}


	public HeroNode getLeftNode() {
    
    
		return leftNode;
	}
	public void setLeftNode(HeroNode leftNode) {
    
    
		this.leftNode=leftNode;
	}
	
	public HeroNode getRightNode() {
    
    
		return rightNode;
	}
	
	public void setRightNode(HeroNode rightNode) {
    
    
		this.rightNode=rightNode;
	}
	
	@Override
	public String toString() {
    
    
		return "HeroNode [leftNode=" + leftNode + ", rightNode=" + rightNode + ", value=" + value + "]";
	}
	
	/**
	 * 三种遍历方法
	 */
	//前序遍历:
	public void frontShow() {
    
    
			System.out.println(this.value);
		if(this.getLeftNode()!=null) {
    
    
			this.getLeftNode().frontShow();
		}
		if(this.getRightNode()!=null) {
    
    
			this.getRightNode().frontShow();
		}
	}
	//中序遍历
	public void middleShow() {
    
    
		if(this.getLeftNode()!=null) {
    
    
			this.getLeftNode().middleShow();
		}
		System.out.println(this.value);
		
		if(this.getRightNode()!=null) {
    
    
			this.getRightNode().middleShow();
		}
	}
	//后序遍历
	public void endShow() {
    
    
		if(this.getLeftNode()!=null) {
    
    
			this.getLeftNode().endShow();
		}
		if(this.getRightNode()!=null) {
    
    
			this.getRightNode().endShow();
		}
		System.out.println(this.value);
	}
	
	public void deleteNode(String value) {
    
    
		if(this.leftNode!=null&&this.leftNode.value.equals(value)) {
    
    
			this.leftNode=null;
			return;
		}
		if(this.rightNode!=null&&this.rightNode.value.equals(value)) {
    
    
			this.rightNode=null;
			return;
		}
		if(this.leftNode!=null) {
    
    
			this.leftNode.deleteNode(value);
		}
		if(this.rightNode!=null) {
    
    
			this.rightNode.deleteNode(value);
		}
	}
}

출력 결과 :
여기에 사진 설명 삽입

추천

출처blog.csdn.net/qq_45273552/article/details/109080302