1. 程式人生 > 其它 >20202301 2021-2022-1 《資料結構與面向物件程式設計》實驗八報告

20202301 2021-2022-1 《資料結構與面向物件程式設計》實驗八報告


課程:《程式設計與資料結構》
班級: 2023
姓名: 賈奕琦
學號:20202301
實驗教師:王志強
實驗日期:2021年11月25日
必修/選修: 必修

## 1.實驗內容

  1. 參考教材PP16.1,完成鏈樹LinkedBinaryTree的實現(getRight,contains,toString,preorder,postorder)
    用JUnit或自己編寫驅動類對自己實現的LinkedBinaryTree進行測試,提交測試程式碼執行截圖,要全屏,包含自己的學號資訊
    課下把程式碼推送到程式碼託管平臺

  2. 基於LinkedBinaryTree,實現基於(中序,先序)序列構造唯一一棵二㕚樹的功能,比如給出中序HDIBEMJNAFCKGL和後序ABDHIEJMNCFGKL,構造出附圖中的樹
    用JUnit或自己編寫驅動類對自己實現的功能進行測試,提交測試程式碼執行截圖,要全屏,包含自己的學號資訊
    課下把程式碼推送到程式碼託管平臺

  3. 自己設計並實現一顆決策樹
    提交測試程式碼執行截圖,要全屏,包含自己的學號資訊
    課下把程式碼推送到程式碼託管平臺

  4. 輸入中綴表示式,使用樹將中綴表示式轉換為字尾表示式,並輸出字尾表示式和計算結果(如果沒有用樹,正常評分。如果用到了樹,即使有小的問題,也酌情給滿分)
    提交測試程式碼執行截圖,要全屏,包含自己的學號資訊

## 2. 實驗過程及結果 <1>參考教材PP16.1,完成鏈樹LinkedBinaryTree的實現(getRight,contains,toString,preorder,postorder)用JUnit或自己編寫驅動類對自己實現的LinkedBinaryTree進行測試,提交測試程式碼執行截圖,要全屏,包含自己的學號資訊,課下把程式碼推送到程式碼託管平臺 程式碼: 節點類:
package tree;

/**
* 鏈式二叉樹結點
* @author Administrator
*/
public class Node<S> {

/**
* 結點值
*/
private char data;
/**
* 左子樹
*/
private Node<S> left;
/**
* 右子樹
*/
private Node<S> right;

public Node(char i,Node left,Node right) {
this.data=data;
this.left=left;
this.right=right;

}
@Override
public String toString() {
return ""+data;
}

public char getData() {
return data;
}
public void setData(char data) {
this.data = data;
}

public Node<S> getLeft() {
return left;
}

public void setLeft(Node<S> left) {
this.left = left;
}

public Node<S> getRight() {
return right;
}

public void setRight(Node<S> right) {
this.right = right;
}
}
LinkedBinaryTree
package tree;

public class LinkedBinaryTree<T> implements BinaryTree {

public LinkedBinaryTree(Node node1) {
this.root=node1;
}

public static class Node{
Object data;
Node left;
Node right;
public Node(Object data){
this.data=data;
this.left=null;
this.right=null;
}
public Node(Object data,Node left,Node right){
this.data=data;
this.left=left;
this.right=right;
}
}

private Node root;



@Override
public int size() {
System.out.print("二叉樹結點的個數是:");
return this.size(root);
}

private int size(Node root) {
if (root == null){
return 0;
}else{
int nl = this.size(root.left);
int nr = this.size(root.right);
return nl+nr+1;
}
}
@Override
public int getHeight() {
System.out.print("二叉樹的高度是:");
return this.getHeight(root);
}

private int getHeight(Node root) {
if (root == null) {
return 0;
} else{
int nl = this.getHeight(root.left);
int nr = this.getHeight(root.right);
return nl>nr?nl+1:nr+1;
}
}
@Override
public Node contains(Object data) {
return this.findKey(data , root);
}

private Node findKey(Object data, Node root) {
if (root == null){//遞迴結束條件1:結點為空,可能是整個樹的根結點,也可能是遞迴呼叫中葉子結點中左孩子和有孩子
return null;

}else if (root !=null && root.data == data){//遞迴結束條件2:找到了
return root;
}else {
//遞迴體
Node node1 = this.findKey(data, root.left);
Node node2 = this.findKey(data, root.right);
if (node1 != null && node1.data == data){
return node1;
}else if (node2 != null && node2.data == data){
return node2;
}else {
return null;
}
}

}
@Override
public void preOrderTraverse() {
System.out.print("先序遍歷:");
preOrderTraverse(root);
System.out.println();
}

private void preOrderTraverse(Node root) {
if (root != null){
//1.輸出跟
System.out.print(root.data+" ");
//2.遍歷左
preOrderTraverse(root.left);
//3.遍歷右
preOrderTraverse(root.right);
}
}
@Override
public void inOrderTraverse() {
System.out.print("中序遍歷:");
inOrderTraverse(root);
System.out.println();
}

private void inOrderTraverse(Node root) {
if (root != null){
//1.遍歷左子樹
this.inOrderTraverse(root.left);
//2.輸出根的值
System.out.print(root.data+" ");
//3.遍歷右子樹
this.inOrderTraverse(root.right);
}
}
@Override
public void postOrderTraverse() {
System.out.print("後序遍歷:");
postOrderTraverse(root);
System.out.println();
}


private void postOrderTraverse(Node node) {
if (node != null){
//1.遍歷左子樹
this.postOrderTraverse(node.left);
//2.遍歷右子樹
this.postOrderTraverse(node.right);
//3.輸出根的值
System.out.print(node.data+" ");
}

}
@Override
public String toString() {
return "" + root.data;
}
@Override
public LinkedBinaryTree<T> getRight(Object data) {
if (root == null) {
System.out.println("空樹");
return null;
}
else if(contains(data)==null){
System.out.println("節點不存在");
return null;
}
else{
LinkedBinaryTree<T> result = new LinkedBinaryTree<T>(root);
result.root = root.right;
return result;
}
}
測試:
package tree;

import org.junit.*;

import java.util.TreeMap;

public class LinkedBinaryTreeTest {
private LinkedBinaryTree.Node node1,node2,node3,node4,node5,node6,node7;
public BinaryTree binaryTree;
@Before
public void setUp() throws Exception {
//建立樹的結點
TreeMap map;
node5 = new LinkedBinaryTree.Node(4,null,null);
node7 = new LinkedBinaryTree.Node(3,null,null);
node3 = new LinkedBinaryTree.Node(2,null,null);
node6 = new LinkedBinaryTree.Node(1,null,node7);
node4 = new LinkedBinaryTree.Node(23,null,node5);
node2 = new LinkedBinaryTree.Node(20,node3,node6);
node1 = new LinkedBinaryTree.Node(20,node4,node2);
//建立二叉樹
binaryTree = new LinkedBinaryTree(node1);

}

@Test
public void size() {
//二叉樹結點的個數是
System.out.println(binaryTree.size());
}

@Test
public void getHeight() {
//二叉樹的高度是
System.out.println(binaryTree.getHeight());
}

@Test
public void findKey() {
System.out.println(binaryTree.contains(23));
}

@Test
public void preOrderTraverse() {
//先序遍歷:20 23 4 20 2 1 3
binaryTree.preOrderTraverse();
}

@Test
public void inOrderTraverse() {
//中序遍歷:23 4 20 2 20 1 3
binaryTree.inOrderTraverse();
}


@Test
public void postOrderTraverse() {
//後序遍歷:4 23 2 3 1 20 20
binaryTree.postOrderTraverse();
}

@Test
public void getRight() {
System.out.println("查詢的節點的右孩子是:"+binaryTree.getRight(20));
System.out.println("查詢的節點的右孩子是:"+binaryTree.getRight(7));
}
}
測試截圖:

樹:

<2> 基於LinkedBinaryTree,實現基於(中序,先序)序列構造唯一一棵二㕚樹的功能,比如給出中序HDIBEMJNAFCKGL和後序ABDHIEJMNCFGKL,構造出附圖中的樹用JUnit或自己編寫驅動類對自己實現的功能進行測試,提交測試程式碼執行截圖,要全屏,包含自己的學號資訊,課下把程式碼推送到程式碼託管平臺

補充方法:

public void  cal_tree(String smid, String slast) {
boolean state = StringEquals(smid, slast);
if (state == false )
return ;
if (smid.length() == 0 )
return ;

if (smid.length() == 1 ) {
res += smid;
return ;
}
char root = slast.charAt(slast.length()- 1 );
int mid = smid.indexOf(root);
String c=smid.substring( 0 , mid);
String d = smid.substring(mid+ 1 );
res += String.valueOf(root);
cal_tree(c,slast.substring( 0 , c.length()));
cal_tree(d,slast.substring(c.length(),slast.length()- 1 ));
return ;
}
public static String res = "";
public static boolean StringEquals(String a1, String a2) {
boolean state = true ;
if (a1.length() != a2.length()) {
state = false ;
}
if (a1.length() == a2.length()) {
for ( int i = 0 ; i < a1.length(); i++) {
if (a2.indexOf(a1.charAt(i)) == - 1 )
state = false ;
}
}
return state;
}
}

測試:

package tree;

import static tree.LinkedBinaryTree.res;

public class test {
public static void main(String[] agrs) {
LinkedBinaryTree linkedBinaryTree=new LinkedBinaryTree(null);
String s1 = "YIJAQ" ;
String s2 = "YIQAJ" ;
linkedBinaryTree.cal_tree(s1, s2);
if (res.length() != s1.length())
{
System.out.println( "wrong tree list!" );
}
else {
System.out.println("前序遍歷為:"+res);
}
}
}
截圖:

樹:

<3>自己設計並實現一顆決策樹,提交測試程式碼執行截圖,要全屏,包含自己的學號資訊,課下把程式碼推送到程式碼託管平臺

程式碼:

package tree;

import java.util.Scanner;

public class DecisionTree {
private static Scanner scanner=new Scanner(System.in);
private static Node1<String> root= new Node1<>("你會不會Java?0/1");

public static void main(String[] args)
{
buildDTree();
runDTree(root);
}
public static void buildDTree(){
root= new Node1<>("你會不會Java?0/1");
Node1<String> temp=root;
temp.left= new Node1<>("不會,放棄嗎?0/1");
temp.right= new Node1<>("會");

temp=temp.left;
temp.left= new Node1<>("絕不放棄!!!");
temp.right= new Node1<>("放棄?0/1");

temp=temp.right;
temp.left= new Node1<>("嘿嘿!不可能的!!!");
temp.right= new Node1<>("中國人不說放棄!!!!");
}

public static void runDTree(Node1 root){
System.out.println(root.data);
if (root.left==null||root.right==null){
return;
}
while (true){
Scanner scanner=new Scanner(System.in);
int slect=scanner.nextInt();

if (slect==1){
runDTree(root.right);
break;
}
else if (slect==0){
runDTree(root.left);
break;
}
else {
System.out.println("輸入錯誤!重新輸入。");
}
}
}
public static class Node1<S> {
private S data;
private Node1<S> left;
private Node1<S> right;

public Node1(S data) {
this.data=data;
}
}
}
執行截圖:

二叉樹:

<4>輸入中綴表示式,使用樹將中綴表示式轉換為字尾表示式,並輸出字尾表示式和計算結果(如果沒有用樹,正常評分。如果用到了樹,即使有小的問題,也酌情給滿分),提交測試程式碼執行截圖,要全屏,包含自己的學號資訊

補充程式碼:

public static class Fix {
static Stack<Character> op = new Stack<>();

public static Float calculate(char op, Float f1, Float f2) {
if (op == '+') return f2 + f1;
else if (op == '-') return f2 - f1;
else if (op == '*') return f2 * f1;
else if (op == '/') return f2 / f1;
else return Float.valueOf(-0);
}

public static float calrp(String rp) {
Stack<Float> v = new Stack<>();
char[] arr = rp.toCharArray();
int len = arr.length;
for (int i = 0; i < len; i++) {
Character ch = arr[i];
if (ch >= '0' && ch <= '9') v.push(Float.valueOf(ch - '0'));
else v.push(calculate(ch, v.pop(), v.pop()));
}
return v.pop();
}

public static String getrp(String s) {
char[] arr = s.toCharArray();
int len = arr.length;
String out = "";
for (int i = 0; i < len; i++) {
char ch = arr[i];
if (ch == ' ') continue;
if (ch >= '0' && ch <= '9') {
out += ch;
continue;
}
if (ch == '(')
op.push(ch);
if (ch == '+' || ch == '-') {
while (!op.empty() && (op.peek() != '('))
out += op.pop();
op.push(ch);
continue;
}
if (ch == '*' || ch == '/') {
while (!op.empty() && (op.peek() == '*' || op.peek() == '/'))
out += op.pop();
op.push(ch);
continue;
}
if (ch == ')') {
while (!op.empty() && op.peek() != '(')
out += op.pop();
op.pop();
continue;
}
}
while (!op.empty()) out += op.pop();
return out;
}
}
測試:
import java.util.Stack;
import java.util.Scanner;
public class TreeShift {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("請輸入表示式:");
String s = scan.nextLine();
Fix fix = new Fix();
System.out.println("字尾表示式為:\n" + Fix.getrp(s));
System.out.println("計算結果為:\n" + fix.calrp(Fix.getrp(s)));
}
執行截圖:

3. 實驗過程中遇到的問題和解決過程

問題1:

一開始看題,沒看懂,那個參考是在哪(手動笑哭)

問題1解決:

仔細翻了翻

其他(感悟、思考等)

這一次實驗涉及到了樹的構建、通過前序與中序構造樹還有決策樹的構建。雖然在最後一箇中綴轉字尾中我沒能用樹的結構來實現,但是通過棧和佇列兩種線性結構來實現這個功能難度依然不小,花費時間較多。這些程式設計實踐能夠讓我們對一些經典的資料結構有更深刻的理解。

參考資料