PAT04-树4 是否同一棵二叉搜索树【JAVA实现】

一、题目内容

给定一个插入序列就可以唯一确定一棵二叉搜索树。然而,一棵给定的二叉搜索树却可以由多种不同的插入序列得到。例如分别按照序列{2, 1, 3}和{2, 3, 1}插入初始为空的二叉搜索树,都得到一样的结果。于是对于输入的各种插入序列,你需要判断它们是否能生成一样的二叉搜索树。

输入格式:

输入包含若干组测试数据。每组数据的第1行给出两个正整数NN (\le 1010)和LL,分别是每个序列插入元素的个数和需要检查的序列个数。第2行给出NNN个以空格分隔的正整数,作为初始插入序列。最后LLL行,每行给出NNN个插入的元素,属于LLL个需要检查的序列。

简单起见,我们保证每个插入序列都是1到NNN的一个排列。当读到NNN为0时,标志输入结束,这组数据不要处理。

输出格式:

对每一组需要检查的序列,如果其生成的二叉搜索树跟对应的初始序列生成的一样,输出“Yes”,否则输出“No”。

输入样例:

4 2
3 1 4 2
3 4 1 2
3 2 4 1
2 1
2 1
1 2
0

输出样例:

Yes
No
No


二、题目分析


(1)首先,应该清楚二叉搜索树的概念:又称二叉查找树(Binary Search Tree),它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。


(2)试想一下二叉排序树的性质,如果对二叉排序树来说,对其进行中序遍历,那么无论一组数字按照怎样的顺序构建,其中序遍历后得到的序列都是一样的。例如题目给的测试实例,{5,6,7,4,3,2}和{5,7,6,3,4,2},他们构造的二叉排序树如下:



(3)一棵二叉树为二叉搜索树的条件是:这棵二叉树中序遍历的数值是依次递增的(节点数值不重复时),因此,为了避免通过中序遍历得到错误的结果,所以我们这里选择通过先序遍历来判断序列生成的二叉搜索树是否相同。



三、编程步骤

(1)读取输入,将每组数据的第一行序列,生成参考的二叉搜索树,并对参考二叉搜索树进行先序遍历,将先序遍历的结果存入参考数组中;当一组数据的输入第一个数据为0时,中止循环;

(2)将每组数据之后的每一行序列,都生成二叉搜索树并生成先序遍历数组;

(3)每生成一个先序遍历数组就与参考数组进行比较,如果相同则输出"Yes",反之则输出"No"。

四、代码分解


(1)读取输入

<span style="font-size:14px;">public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		char n = 1;
		while (scan.hasNext()) {
			BinSearchNode1 head = new BinSearchNode1();//参考二叉搜索树
			int col = Integer.parseInt(scan.next());
			String[] arr = new String[col];
			if (col == 0) {//当一组数据以0为开始时,则跳出循环
				break;
			}
			// 读入初始序列,生成二叉搜索树,输出中序遍历数组
			int row = Integer.parseInt(scan.next());
			for (int i = 0; i < col; i++) {
				head.insert(scan.next());
			}
			//参考二叉搜索树的先序遍历数组
			arr = proorder(head,col);//初始序列生成二叉搜索树的中序遍历数组
			// 将需要检查的序列生成二叉搜索树,进行中序遍历,判断是否与初始序列生成同一棵二叉搜索树
			for (int j = 0; j < row; j++) {
				head = new BinSearchNode1();//需要检测的二叉搜索树
				String[] arr2 = new String[col];
				for (int i = 0; i < col; i++) {
					head.insert(scan.next());
				}
				arr2 = proorder(head,col);//需要检测的二叉搜索树的先序遍历数组
				String result = isEqual(arr, arr2, col)?"Yes":"No";
				if (n == 1) {
					System.out.print(result);
					n = 2;
				}else{
					System.out.print("\n"+result);
				}
			}
		}
	}</span>

(2)生成二叉搜索树类,以及插入方法

<span style="font-size:14px;">class BinSearchNode1 {
	String data;
	BinSearchNode1 left;
	BinSearchNode1 right;
	
	public BinSearchNode1() {
		
	}

	/*
	 * 插入方法:向二叉搜索树中插入节点,并且返回二叉搜索树的根节点 如果根节点为空,则将值直接插入根节点中;
	 * 如果根节点不为空,则将值与根节点中的值进行比较, 如果大则让根节点跳转到右孩子上;如果小则让根节点跳转到左孩子上。
	 */
	public void insert(String s) {
		if (data == null) {
			data = s;
			return;
		}
		BinSearchNode1 bin = new BinSearchNode1();
		bin.data = s;
		BinSearchNode1 head = this;
		while (head != null) {
			if (Integer.parseInt(s) == Integer.parseInt(head.data)) {
				return;
			}
			if (Integer.parseInt(s) > Integer.parseInt(head.data)) {
				if (head.right == null) {
					head.right = bin;
					return;
				}
				head = head.right;
			} else {
				if (head.left == null) {
					head.left = bin;
					return;
				}
				head = head.left;
			}
		}
	}
}</span>

(3)这里对二叉搜索树进行先序遍历采用的是非递归方法,使用堆栈:

下面包括堆栈类,以及入栈,出栈,判断堆栈为空,判断堆栈已满等操作:


<span style="font-size:14px;">class stack3 {
	public BinSearchNode1[] data;
	public int capacity;
	public int top;

	// 构造函数
	public stack3(int max) {
		top = -1;
		capacity = max;
		data = new BinSearchNode1[max];
	}

	// 入栈操作
	public void push(BinSearchNode1 value) {
		if (isFull()) {
			System.out.println("堆栈已满!");
		} else {
			data[++top] = value;
		}
	}

	// 出栈操作
	public BinSearchNode1 pop() {
		if (isEmpty()) {
			return null;
		} else {
			return data[top--];
		}
	}
	// 取出堆栈最上面的数

		// 判断堆栈是否已满
		public boolean isFull() {
			if (top == capacity - 1) {
				return true;
			} else {
				return false;
			}
		}
		// 判断堆栈是否为空
		public boolean isEmpty() {
			if (top == -1) {
				return true;
			} else {
				return false;
			}
		}
}
</span>


(4)使用堆栈实现二叉搜索树的先序遍历

  • 创建一个栈,先将头结点压入;
  • 从堆栈中弹出栈项节点,再将结点的右孩子(如果不为空)压入;再将结点的左孩子(如果不为空)压入;
  • 重复步骤2,直到堆栈为空结束。
<span style="font-size:14px;">public static String[] proorder(BinSearchNode1 head,int num) {
		String pro[] = new String[num]; 
		int n = 0;
		if (head != null) {
			stack3 stack = new stack3(num);
			stack.push(head);
			head = stack.pop();
			while (head != null) {
				pro[n++] = head.data;
				if (head.right != null) {
					stack.push(head.right);
				}
				if (head.left != null) {
					stack.push(head.left);
				}
				head = stack.pop();
			}
		}
		return pro;
	}</span>

(5)全部代码
<span style="font-size:14px;">package struct;

import java.util.Scanner;

/*
 * 判断一棵二叉树为二叉搜索树的条件是:这棵二叉树中序遍历的数值是依次递增的(节点数值不重复时)。
 * 判断两个序列是否为同一二叉搜索树就需要将两个序列分别生成二叉树之后,
 * 再进行先序或者后序遍历,如果一样就是相同的,否则不是。
 */
class BinSearchNode1 {
	String data;
	BinSearchNode1 left;
	BinSearchNode1 right;

	public BinSearchNode1() {

	}

	/*
	 * 插入方法:向二叉搜索树中插入节点,并且返回二叉搜索树的根节点 如果根节点为空,则将值直接插入根节点中;
	 * 如果根节点不为空,则将值与根节点中的值进行比较, 如果大则让根节点跳转到右孩子上;如果小则让根节点跳转到左孩子上。
	 */
	public void insert(String s) {
		if (data == null) {
			data = s;
			return;
		}
		BinSearchNode1 bin = new BinSearchNode1();
		bin.data = s;
		BinSearchNode1 head = this;
		while (head != null) {
			if (Integer.parseInt(s) == Integer.parseInt(head.data)) {
				return;
			}
			if (Integer.parseInt(s) > Integer.parseInt(head.data)) {
				if (head.right == null) {
					head.right = bin;
					return;
				}
				head = head.right;
			} else {
				if (head.left == null) {
					head.left = bin;
					return;
				}
				head = head.left;
			}
		}
	}
}

class stack3 {
	public BinSearchNode1[] data;
	public int capacity;
	public int top;

	// 构造函数
	public stack3(int max) {
		top = -1;
		capacity = max;
		data = new BinSearchNode1[max];
	}

	// 入栈操作
	public void push(BinSearchNode1 value) {
		if (isFull()) {
			System.out.println("堆栈已满!");
		} else {
			data[++top] = value;
		}
	}

	// 出栈操作
	public BinSearchNode1 pop() {
		if (isEmpty()) {
			return null;
		} else {
			return data[top--];
		}
	}

	// 取出堆栈最上面的数
	public BinSearchNode1 top() {
		if (isEmpty()) {
			return null;
		} else {
			return data[top];
		}
	}

	// 判断堆栈是否已满
	public boolean isFull() {
		if (top == capacity - 1) {
			return true;
		} else {
			return false;
		}
	}

	// 判断堆栈是否为空
	public boolean isEmpty() {
		if (top == -1) {
			return true;
		} else {
			return false;
		}
	}
}

public class SameSearchTree {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		char n = 1;
		while (scan.hasNext()) {
			BinSearchNode1 head = new BinSearchNode1();// 参考二叉搜索树
			int col = Integer.parseInt(scan.next());
			String[] arr = new String[col];
			if (col == 0) {// 当一组数据以0为开始时,则跳出循环
				break;
			}
			// 读入初始序列,生成二叉搜索树,输出中序遍历数组
			int row = Integer.parseInt(scan.next());
			for (int i = 0; i < col; i++) {
				head.insert(scan.next());
			}
			// 参考二叉搜索树的先序遍历数组
			arr = proorder(head, col);// 初始序列生成二叉搜索树的中序遍历数组
			// 将需要检查的序列生成二叉搜索树,进行中序遍历,判断是否与初始序列生成同一棵二叉搜索树
			for (int j = 0; j < row; j++) {
				head = new BinSearchNode1();// 需要检测的二叉搜索树
				String[] arr2 = new String[col];
				for (int i = 0; i < col; i++) {
					head.insert(scan.next());
				}
				arr2 = proorder(head, col);// 需要检测的二叉搜索树的先序遍历数组
				String result = isEqual(arr, arr2, col) ? "Yes" : "No";
				if (n == 1) {
					System.out.print(result);
					n = 2;
				} else {
					System.out.print("\n" + result);
				}
			}
		}
	}

	/*
	 * 比较两个数组是否相等
	 */
	public static boolean isEqual(String[] arr1, String[] arr2, int col) {
		for (int i = 0; i < col; i++) {
			if (!arr1[i].equals(arr2[i])) {
				return false;
			}
		}
		return true;
	}

	/*
	 * 先序遍历,使用非递归方法实现; 1、创建一个栈,先将头结点压入;
	 * 2、从堆栈中弹出栈项节点,再将结点的右孩子(如果不为空)压入;再将结点的左孩子(如果不为空)压入; 3、重复步骤2,直到堆栈为空结束。
	 */
	public static String[] proorder(BinSearchNode1 head, int num) {
		String pro[] = new String[num];
		int n = 0;
		if (head != null) {
			stack3 stack = new stack3(num);
			stack.push(head);
			head = stack.pop();
			while (head != null) {
				pro[n++] = head.data;
				if (head.right != null) {
					stack.push(head.right);
				}
				if (head.left != null) {
					stack.push(head.left);
				}
				head = stack.pop();
			}
		}
		return pro;
	}
}
</span>





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值