21-30天

学习Java第21天

二叉树的深度遍历的递归实现

目标:
21.1 二叉树的遍历比存储、建立要简单. 所以先“手动”建立一个二叉树来玩.
21.2 递归算法写起来就是舒服. 前、中、后序的代码差别只有输出语句的位置.
21.3 不需要额外的节点类, 每棵二叉树 (树) 都可以从自己的根结点找到其它所有节点. 这个需要自悟.
21.4 获取二叉树的层次、总节点数, 也需要递归. 以后可能要用, 这里就一并写了.

代码如下:

import java.util.Arrays;

public class BinaryCharTree {
	char value;
	BinaryCharTree leftChild;
	BinaryCharTree rightChild;
	public BinaryCharTree(char paraName) {
		value = paraName;
		leftChild = null;
		rightChild = null;
	}//constructor
	
	public static BinaryCharTree manualConstructTree() {
		// Step 1. Construct a tree with only one node.
		BinaryCharTree resultTree = new BinaryCharTree('a');

		// Step 2. Construct all nodes. The first node is the root.
		// BinaryCharTreeNode tempTreeA = resultTree.root;
		BinaryCharTree tempTreeB = new BinaryCharTree('b');
		BinaryCharTree tempTreeC = new BinaryCharTree('c');
		BinaryCharTree tempTreeD = new BinaryCharTree('d');
		BinaryCharTree tempTreeE = new BinaryCharTree('e');
		BinaryCharTree tempTreeF = new BinaryCharTree('f');
		BinaryCharTree tempTreeG = new BinaryCharTree('g');

		// Step 3. Link all nodes.
		resultTree.leftChild = tempTreeB;
		resultTree.rightChild = tempTreeC;
		tempTreeB.rightChild = tempTreeD;
		tempTreeC.leftChild = tempTreeE;
		tempTreeD.leftChild = tempTreeF;
		tempTreeD.rightChild = tempTreeG;

		return resultTree;
	}//manualConstructTree
	
	public void preOrderVisit() {
		System.out.print("" + value + " ");

		if (leftChild != null) {
			leftChild.preOrderVisit();
		} //if

		if (rightChild != null) {
			rightChild.preOrderVisit();
		} //if
	}//preOrderVisit
	
	public void inOrderVisit() {
		if (leftChild != null) {
			leftChild.inOrderVisit();
		} //if

		System.out.print("" + value + " ");

		if (rightChild != null) {
			rightChild.inOrderVisit();
		} //if
	}//inOrderVisit
	
	public void postOrderVisit() {
		if (leftChild != null) {
			leftChild.postOrderVisit();
		} //if

		if (rightChild != null) {
			rightChild.postOrderVisit();
		} //if

		System.out.print("" + value + " ");
	}//postOrderVisit
	
	public int getDepth() {
		// It is a leaf.
		if ((leftChild == null) && (rightChild == null)) {
			return 1;
		} //if

		// The depth of the left child.
		int tempLeftDepth = 0;
		if (leftChild != null) {
			tempLeftDepth = leftChild.getDepth();
		} //if

		// The depth of the right child.
		int tempRightDepth = 0;
		if (rightChild != null) {
			tempRightDepth = rightChild.getDepth();
		} //if

		// The depth should increment by 1.
		if (tempLeftDepth >= tempRightDepth) {
			return tempLeftDepth + 1;
		} else {
			return tempRightDepth + 1;
		} // if
	}//getDepth
	
	public int getNumNodes() {
		// It is a leaf.
		if ((leftChild == null) && (rightChild == null)) {
			return 1;
		} //if

		// The number of nodes of the left child.
		int tempLeftNodes = 0;
		if (leftChild != null) {
			tempLeftNodes = leftChild.getNumNodes();
		} //if

		// The number of nodes of the right child.
		int tempRightNodes = 0;
		if (rightChild != null) {
			tempRightNodes = rightChild.getNumNodes();
		} //if

		// The total number of nodes.
		return tempLeftNodes + tempRightNodes + 1;
	}//getNumNodes
	
	public static void main(String args[]) {
		BinaryCharTree tempTree = manualConstructTree();
		System.out.println("\r\nPreorder visit:");
		tempTree.preOrderVisit();
		System.out.println("\r\nIn-order visit:");
		tempTree.inOrderVisit();
		System.out.println("\r\nPost-order visit:");
		tempTree.postOrderVisit();

		System.out.println("\r\n\r\nThe depth is: " + tempTree.getDepth());
		System.out.println("The number of nodes is: " + tempTree.getNumNodes());
	}//main

}

运行结果:

Preorder visit:
a b d f g c e 
In-order visit:
b f d g a e c 
Post-order visit:
f g d b e c a 

The depth is: 4
The number of nodes is: 7

什么是二叉树?二叉树的性质

学习Java第22天

二叉树的存储

目标:
二叉树的存储并非一个简单的问题. 引用 (指针) 是无法存储到文件里面的.
我们可以完全满二叉树的角度广度优先遍历的角度来考虑这个问题: 每个节点都有一个 name 及其在二叉树中的位置. 令根节点的位置为 0; 则第 2 层节点的位置依次为 1 至 2; 第 3 层节点的位置依次为 3 至 6. 以此类推.

代码如下:

import java.util.Arrays;

public class CircleObjectQueue {
	public static final int TOTAL_SPACE = 10;
	Object[] data;
	int head;
	int tail;
	BinaryCharTree leftChild;
	BinaryCharTree rightChild;
	
	public CircleObjectQueue() {
		data = new Object[TOTAL_SPACE];
		head = 0;
		tail = 0;
	}//first constructor
	
	public static BinaryCharTree manualConstructTree() {
		// Step 1. Construct a tree with only one node.
		BinaryCharTree resultTree = new BinaryCharTree('a');

		// Step 2. Construct all nodes. The first node is the root.
		// BinaryCharTreeNode tempTreeA = resultTree.root;
		BinaryCharTree tempTreeB = new BinaryCharTree('b');
		BinaryCharTree tempTreeC = new BinaryCharTree('c');
		BinaryCharTree tempTreeD = new BinaryCharTree('d');
		BinaryCharTree tempTreeE = new BinaryCharTree('e');
		BinaryCharTree tempTreeF = new BinaryCharTree('f');
		BinaryCharTree tempTreeG = new BinaryCharTree('g');

		// Step 3. Link all nodes.
		resultTree.leftChild = tempTreeB;
		resultTree.rightChild = tempTreeC;
		tempTreeB.rightChild = tempTreeD;
		tempTreeC.leftChild = tempTreeE;
		tempTreeD.leftChild = tempTreeF;
		tempTreeD.rightChild = tempTreeG;

		return resultTree;
	}//manualConstructTree
	
	public void enqueue(Object paraValue) {
		if ((tail + 1) % TOTAL_SPACE == head) {
			System.out.println("Queue full.");
			return;
		}//if
		
		data[tail % TOTAL_SPACE] = paraValue;
		tail++;
	}//enqueue
	
	public Object dequeue() {
		if (head == tail) {
			//System.out.println("No element in the queue");
			return null;
		}//if
		
		Object resultValue = data[head];
		head++;
		return resultValue;
	}//dequeue
	
	public String toString() {
		String resultString = "";
		if (head == tail) {
			return "empty";
		}//if
		
		for (int i = head; i < tail; i++) {
			resultString += data[i % TOTAL_SPACE] + ", ";
		}//i
		return resultString;
	}//toString
	
	char[] valuesArray;
	int[] indicesArray;
	
	public int getNumNodes() {
		// It is a leaf.
		if ((leftChild == null) && (rightChild == null)) {
			return 1;
		} //if

		// The number of nodes of the left child.
		int tempLeftNodes = 0;
		if (leftChild != null) {
			tempLeftNodes = leftChild.getNumNodes();
		} //if

		// The number of nodes of the right child.
		int tempRightNodes = 0;
		if (rightChild != null) {
			tempRightNodes = rightChild.getNumNodes();
		} //if

		// The total number of nodes.
		return tempLeftNodes + tempRightNodes + 1;
	}//getNumNodes
	
	public void toDataArrays() {
		//Initialize arrays.
		int tempLength = getNumNodes();

		valuesArray = new char[tempLength];
		indicesArray = new int[tempLength];
		int i = 0;

		//Traverse and convert at the same time.
		CircleObjectQueue tempQueue = new CircleObjectQueue();
		tempQueue.enqueue(this);
		CircleIntQueue tempIntQueue = new CircleIntQueue();
		tempIntQueue.enqueue(0);

		BinaryCharTree tempTree = (BinaryCharTree) tempQueue.dequeue();
		int tempIndex = tempIntQueue.dequeue();
		while (tempTree != null) {
			valuesArray[i] = tempTree.value;
			indicesArray[i] = tempIndex;
			i++;

			if (tempTree.leftChild != null) {
				tempQueue.enqueue(tempTree.leftChild);
				tempIntQueue.enqueue(tempIndex * 2 + 1);
			} //if

			if (tempTree.rightChild != null) {
				tempQueue.enqueue(tempTree.rightChild);
				tempIntQueue.enqueue(tempIndex * 2 + 2);
			} //if

			tempTree = (BinaryCharTree) tempQueue.dequeue();
			tempIndex = tempIntQueue.dequeue();
		} //while
	}//toDataArrays
	
	public static void main(String args[]) {
		CircleObjectQueue tempQueue = new CircleObjectQueue();
		BinaryCharTree tempTree = manualConstructTree();
		System.out.println("\r\nPreorder visit:");
		tempTree.preOrderVisit();
		System.out.println("\r\nIn-order visit:");
		tempTree.inOrderVisit();
		System.out.println("\r\nPost-order visit:");
		tempTree.postOrderVisit();

		System.out.println("\r\n\r\nThe depth is: " + tempTree.getDepth());
		System.out.println("The number of nodes is: " + tempTree.getNumNodes());

		tempTree.toDataArrays();
		System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
		System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));
		
	}//main
}

心得:

今天的内容很多需要在昨天的基础上进行,但是还有几个问题需要深度理解后才能解决。

学习Java第23天

任务:
1.Java 里面, 所有的类均为 Object 类的 (直接或间接) 子类. 如果不写就默认为直接子类. 例如
public class CircleObjectQueue;
等价于
public class CircleObjectQueue extends Object;
2.存储对象的队列, 实际上是存储对象的地址 (引用、指针). 因此, 可以存储任何类的对象 (的引用).
3.可以通过强制类型转换将对象转成其本身的类别. 例如前面程序
tempTree = (BinaryCharTree) tempQueue.dequeue();
4.括号中的类型即表示强制类型转换.
Java 本身将 int, double, char 分别封装到 Integer, Double, Char 类.

今天的代码在昨天基础上进行
新的部分代码如下:

public class toDataArraysObjectQueue{
	// Initialize arrays.
			int tempLength = getNumNodes();
	 
			valuesArray = new char[tempLength];
			indicesArray = new int[tempLength];
			int i = 0;
	 
			// Traverse and convert at the same time.
			CircleObjectQueue tempQueue = new CircleObjectQueue();
			tempQueue.enqueue(this);
			CircleObjectQueue tempIntQueue = new CircleObjectQueue();
			Integer tempIndexInteger = new Integer(0);
			tempIntQueue.enqueue(tempIndexInteger);
	 
			BinaryCharTree tempTree = (BinaryCharTree) tempQueue.dequeue();
			int tempIndex = ((Integer) tempIntQueue.dequeue()).intValue();
			System.out.println("tempIndex = " + tempIndex);
			while (tempTree != null) {
				valuesArray[i] = tempTree.value;
				indicesArray[i] = tempIndex;
				i++;
	 
				if (tempTree.leftChild != null) {
					tempQueue.enqueue(tempTree.leftChild);
					tempIntQueue.enqueue(new Integer(tempIndex * 2 + 1));
				} // Of if
	 
				if (tempTree.rightChild != null) {
					tempQueue.enqueue(tempTree.rightChild);
					tempIntQueue.enqueue(new Integer(tempIndex * 2 + 2));
				} // Of if
	 
				tempTree = (BinaryCharTree) tempQueue.dequeue();
				if (tempTree == null) {
					break;
				}//Of if
				
				tempIndex = ((Integer) tempIntQueue.dequeue()).intValue();
			} // Of while
		}// Of toDataArraysObjectQueue
	public static void main(String args[]) {
			BinaryCharTree tempTree = manualConstructTree();
			System.out.println("\r\nPreorder visit:");
			tempTree.preOrderVisit();
			System.out.println("\r\nIn-order visit:");
			tempTree.inOrderVisit();
			System.out.println("\r\nPost-order visit:");
			tempTree.postOrderVisit();
	 
			System.out.println("\r\n\r\nThe depth is: " + tempTree.getDepth());
			System.out.println("The number of nodes is: " + tempTree.getNumNodes());
			
			tempTree.toDataArrays();
			System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
			System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));
			tempTree.toDataArraysObjectQueue();
			System.out.println("Only object queue.");
			System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
			System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));
	}


二叉树这块理解的不太好,需要多看看。

学习Java第24天

二叉树的建立

只增加了一个构造方法, 相当于第 22 天的逆过程.
保留了调拭语句, 因为下标很容易出错.
使用一个线性表先分配所有节点的空间, 再将节点链接起来.
最后并没有返回, 而是把第 0 个节点的相应值拷贝给自己.

代码如下:

public class BinaryCharTree24 {

	public BinaryCharTree(char[] paraDataArray, int[] paraIndicesArray) {
		// Step 1. Use a sequential list to store all nodes.
		int tempNumNodes = paraDataArray.length;
		BinaryCharTree[] tempAllNodes = new BinaryCharTree[tempNumNodes];
		for (int i = 0; i < tempNumNodes; i++) {
			tempAllNodes[i] = new BinaryCharTree(paraDataArray[i]);
		} //i

		// Step 2. Link these nodes.
		for (int i = 1; i < tempNumNodes; i++) {
			for (int j = 0; j < i; j++) {
				System.out.println("indices " + paraIndicesArray[j] + " vs. " + paraIndicesArray[i]);
				if (paraIndicesArray[i] == paraIndicesArray[j] * 2 + 1) {
					tempAllNodes[j].leftChild = tempAllNodes[i];
					System.out.println("Linking " + j + " with " + i);
					break;
				} else if (paraIndicesArray[i] == paraIndicesArray[j] * 2 + 2) {
					tempAllNodes[j].rightChild = tempAllNodes[i];
					System.out.println("Linking " + j + " with " + i);
					break;
				} //if
			} //j
		} //i
		
		//Step 3. The root is the first node.
		value = tempAllNodes[0].value;
		leftChild = tempAllNodes[0].leftChild;
		rightChild = tempAllNodes[0].rightChild;
	}//the the second constructor


	public static void main(String args[]) {
		BinaryCharTree tempTree = manualConstructTree();
		System.out.println("\r\nPreorder visit:");
		tempTree.preOrderVisit();
		System.out.println("\r\nIn-order visit:");
		tempTree.inOrderVisit();
		System.out.println("\r\nPost-order visit:");
		tempTree.postOrderVisit();

		System.out.println("\r\n\r\nThe depth is: " + tempTree.getDepth());
		System.out.println("The number of nodes is: " + tempTree.getNumNodes());

		tempTree.toDataArrays();
		System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
		System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));

		tempTree.toDataArraysObjectQueue();
		System.out.println("Only object queue.");
		System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
		System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));
		
		char[] tempCharArray = {'A', 'B', 'C', 'D', 'E', 'F'};
		int[] tempIndicesArray = {0, 1, 2, 4, 5, 12};
		BinaryCharTree tempTree2 = new BinaryCharTree(tempCharArray, tempIndicesArray);

		System.out.println("\r\nPreorder visit:");
		tempTree2.preOrderVisit();
		System.out.println("\r\nIn-order visit:");
		tempTree2.inOrderVisit();
		System.out.println("\r\nPost-order visit:");
		tempTree2.postOrderVisit();
	}//main

}

有点难以吃透二叉树

学习Java第25天

二叉树深度遍历的栈实现 (中序)

任务:

25.1具有通用性的对象栈:

改写栈程序, 里面存放对象.
该程序应该放在 datastructure.stack 包内.
还是依靠强制类型转换, 支持不同的数据类型.
增加了 isEmpty() 方法.

代码如下:

public class ObjectStack {

		public static final int MAX_DEPTH = 10;
		int depth;

		Object[] data;

		public ObjectStack() {
			depth = 0;
			data = new Object[MAX_DEPTH];
		}//first constructor

		public String toString() {
			String resultString = "";
			for (int i = 0; i < depth; i++) {
				resultString += data[i];
			} //i

			return resultString;
		}//toString

		public boolean push(Object paraObject) {
			if (depth == MAX_DEPTH) {
				System.out.println("Stack full.");
				return false;
			} //if

			data[depth] = paraObject;
			depth++;

			return true;
		}//push

	public Object pop() {
			if (depth == 0) {
				System.out.println("Nothing to pop.");
				return '\0';
			} //if

			Object resultObject = data[depth - 1];
			depth--;

			return resultObject;
		}//pop

		public boolean isEmpty() {
			if (depth == 0) {
				return true;
			}//Of if

			return false;
		}//isEmpty
		
		public static void main(String args[]) {
			ObjectStack tempStack = new ObjectStack();

			for (char ch = 'a'; ch < 'm'; ch++) {
				tempStack.push(new Character(ch));
				System.out.println("The current stack is: " + tempStack);
			} //i

			char tempChar;
			for (int i = 0; i < 12; i++) {
				tempChar = ((Character)tempStack.pop()).charValue();
				System.out.println("Poped: " + tempChar);
				System.out.println("The current stack is: " + tempStack);
			} //i
		}//main
	

运行结果:

The current stack is: a
The current stack is: ab
The current stack is: abc
The current stack is: abcd
The current stack is: abcde
The current stack is: abcdef
The current stack is: abcdefg
The current stack is: abcdefgh
The current stack is: abcdefghi
The current stack is: abcdefghij
Stack full.
The current stack is: abcdefghij
Stack full.
The current stack is: abcdefghij
Poped: j
The current stack is: abcdefghi
Poped: i
The current stack is: abcdefgh
Poped: h
The current stack is: abcdefg
Poped: g
The current stack is: abcdef
Poped: f
The current stack is: abcde
Poped: e
The current stack is: abcd
Poped: d
The current stack is: abc
Poped: c
The current stack is: ab
Poped: b
The current stack is: a
Poped: a
The current stack is: 
Nothing to pop.
Poped: 

25.2 中序遍历

	public void inOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		while (!tempStack.isEmpty() || tempNode != null) {
			if (tempNode != null) {
				tempStack.push(tempNode);
				tempNode = tempNode.leftChild;
			} else {
				tempNode = (BinaryCharTree) tempStack.pop();
				System.out.print("" + tempNode.value + " ");
				tempNode = tempNode.rightChild;
			} //if
		} //while
	}//inOrderVisit

	public static void main(String args[]) {
		BinaryCharTree tempTree = manualConstructTree();
		System.out.println("\r\nPreorder visit:");
		tempTree.preOrderVisit();
		System.out.println("\r\nIn-order visit:");
		tempTree.inOrderVisit();
		System.out.println("\r\nPost-order visit:");
		tempTree.postOrderVisit();

		System.out.println("\r\n\r\nThe depth is: " + tempTree.getDepth());
		System.out.println("The number of nodes is: " + tempTree.getNumNodes());

		tempTree.toDataArrays();
		System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
		System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));

		tempTree.toDataArraysObjectQueue();
		System.out.println("Only object queue.");
		System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
		System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));

		char[] tempCharArray = { 'A', 'B', 'C', 'D', 'E', 'F' };
		int[] tempIndicesArray = { 0, 1, 2, 4, 5, 12 };
		BinaryCharTree tempTree2 = new BinaryCharTree(tempCharArray, tempIndicesArray);

		System.out.println("\r\nPre-order visit:");
		tempTree2.preOrderVisit();
		System.out.println("\r\nIn-order visit:");
		tempTree2.inOrderVisit();
		System.out.println("\r\nPost-order visit:");
		tempTree2.postOrderVisit();

		System.out.println("\r\nIn-order visit with stack:");
		tempTree2.inOrderVisitWithStack();
	}//main

中序遍历这里好像是需要和前几天的代码联系起来才行,二叉树这里问题还有点多,需要加强理解。

学习Java第26天

二叉树深度遍历的栈实现 (前序和后序)

前序与中序的区别, 仅仅在于输出语句的位置不同.
二叉树的遍历, 总共有 6 种排列: 1) 左中右 (中序); 2) 左右中 (后序); 3) 中左右 (前序); 4) 中右左; 5) 右左中; 6) 右中左. 我们平常关心的是前三种, 是因为我们习惯于先左后右. 如果要先右后左, 就相当于左右子树互换, 这个是很容易做到的.
如果将前序的左右子树互换, 就可得到 4) 中右左; 再进行逆序, 可以得到 2) 左右中. 因此, 要把前序的代码改为后序, 需要首先将 leftChild 和 rightChild 互换, 然后用一个栈来存储需要输出的字符, 最终反向输出即可. 这种将一个问题转换成另一个等价问题的方式, 无论在数学还是计算机领域, 都极度重要. 参见 https://blog.csdn.net/minfanphd/article/details/117318844 中莫峦奇的版本.
如果不按上述方式, 直接写后序遍历, 就会复杂得多, 有双重的 while 循环. 参见 https://blog.csdn.net/minfanphd/article/details/117318844 中潘佳豪的版本.

新代码如下:

public class days26 {

	public void preOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		while (!tempStack.isEmpty() || tempNode != null) {
			if (tempNode != null) {
				System.out.print("" + tempNode.value + " ");
				tempStack.push(tempNode);
				tempNode = tempNode.leftChild;
			} else {
				tempNode = (BinaryCharTree) tempStack.pop();
				tempNode = tempNode.rightChild;
			} //if
		} //while
	}//preOrderVisitWithStack

	public void postOrderVisitWithStack() {
		ObjectStack tempStack = new ObjectStack();
		BinaryCharTree tempNode = this;
		ObjectStack tempOutputStack = new ObjectStack();
		
		while (!tempStack.isEmpty() || tempNode != null) {
			if (tempNode != null) {
				//Store for output.
				tempOutputStack.push(new Character(tempNode.value));
				tempStack.push(tempNode);
				tempNode = tempNode.rightChild;
			} else {
				tempNode = (BinaryCharTree) tempStack.pop();
				tempNode = tempNode.leftChild;
			} //if
		} //while
		
		//Now reverse output.
		while (!tempOutputStack.isEmpty()) {
			System.out.print("" + tempOutputStack.pop() + " ");
		}//while
	}//postOrderVisitWithStack

	public static void main(String args[]) {
		BinaryCharTree tempTree = manualConstructTree();
		System.out.println("\r\nPreorder visit:");
		tempTree.preOrderVisit();
		System.out.println("\r\nIn-order visit:");
		tempTree.inOrderVisit();
		System.out.println("\r\nPost-order visit:");
		tempTree.postOrderVisit();

		System.out.println("\r\n\r\nThe depth is: " + tempTree.getDepth());
		System.out.println("The number of nodes is: " + tempTree.getNumNodes());

		tempTree.toDataArrays();
		System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
		System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));

		tempTree.toDataArraysObjectQueue();
		System.out.println("Only object queue.");
		System.out.println("The values are: " + Arrays.toString(tempTree.valuesArray));
		System.out.println("The indices are: " + Arrays.toString(tempTree.indicesArray));

		char[] tempCharArray = { 'A', 'B', 'C', 'D', 'E', 'F' };
		int[] tempIndicesArray = { 0, 1, 2, 4, 5, 12 };
		BinaryCharTree tempTree2 = new BinaryCharTree(tempCharArray, tempIndicesArray);

		System.out.println("\r\nPre-order visit:");
		tempTree2.preOrderVisit();
		System.out.println("\r\nIn-order visit:");
		tempTree2.inOrderVisit();
		System.out.println("\r\nPost-order visit:");
		tempTree2.postOrderVisit();

		System.out.println("\r\nIn-order visit with stack:");
		tempTree2.inOrderVisitWithStack();
		System.out.println("\r\nPre-order visit with stack:");
		tempTree2.preOrderVisitWithStack();
		System.out.println("\r\nPost-order visit with stack:");
		tempTree2.postOrderVisitWithStack();
	}//main

}

在使用之前几天的代码都要重新复制一遍,有没有能直接引用文件函数的方法简便操作呢

Days 27:Hanoi 塔问题

递归调用的问题
有A,B,C三个柱子,A柱子上有n个圆盘(从上到下,圆盘大小逐渐变大),要把它移动到B柱子上。
每次移动,都必须保证小圆盘放在大圆盘上面
每次也只能移动一个圆盘
如果n = 1 n=1n=1的话,就可以直接把A柱上的一个圆盘移动到B柱上,就结束了
如果n = 2 n=2n=2的话,得先把上面一个移动到C柱上,然后再把A柱上剩下的一个移动到B柱上,最后再把C柱上的那一个移动到B柱上。
如果n = 3 n=3n=3的话,得先把上面2 22个移动到C柱上,然后再把A柱上剩下的一个移动到B柱上,最后再把C柱上的那2个移动到B柱上。
如果n = n n=nn=n的话,得先把上面n − 1 n-1n−1个移动到C柱上,然后再把A柱上剩下的一个移动到B柱上,最后再把C柱上的那n − 1 n-1n−1个移动到B柱上。

本次实验是三个圆盘,三个柱子

代码如下:

public class days27_Hanoi {

		public static void hanoi(char paraSource, char paraIntermediary, char paraDestination,
				int paraNumber) {
			if (paraNumber == 1) {
				System.out.println(paraSource + "->" + paraDestination + " ");
				return;
			} //if

			hanoi(paraSource, paraDestination, paraIntermediary, paraNumber - 1);
			System.out.println(paraSource + "->" + paraDestination + " ");
			hanoi(paraIntermediary, paraSource, paraDestination, paraNumber - 1);
		}//hanoi

		public static void main(String args[]) {
			hanoi('a', 'b', 'c', 3);
		}//main

}

运行结果:

a->c 
a->b 
c->b 
a->c 
b->a 
b->c 
a->c 

配合着问题来看,代码就好理解一些了

第 28 天: Huffman 编码 (节点定义与文件读取)

目标:
定义了一个内嵌类. 如果是实际项目, 我就为其单独写一个文件了, 这里仅仅是为了方便.
每个节点的内容包括: 字符 (仅对叶节点有效)、权重 (用的整数, 该字符的个数)、指向子节点父节点的引用. 这里指向父节点的引用是必须的.
NUM_CHARS 是指 ASCII 字符集的字符个数. 为方便起见, 仅支持 ASCII.
inputText 的引入只是想把程序尽可能细分成独立的模块, 这样便于学习和调拭.
alphabet 仅存 inputText 出现过的字符.
alphabetLength 完全可以用 alphabet.length() 代替, 但我就喜欢写成独立的变量.
charCounts 要为所有的节点负责, 其元素对应于 HuffmanNode 里面的 weight. 为了节约, 可以把其中一个省掉.
charMapping 是为了从 ASCII 里面的顺序映射到 alphabet 里面的顺序. 这也是我只采用 ASCII 字符集 (仅 256 字符) 的原因.
huffmanCodes 将个字符映射为一个字符串, 其实应该是二进制串. 我这里不是想偷懒么.
nodes 要先把所有的节点存储在一个数组里面, 然后再链接它们. 这是常用招数.
构造方法仅初始化了 charMapping, 读入了文件.
readText 采用了最简单粗暴的方式. 还可以有其它的逐行读入的方式.
要自己弄个文本文件, 里面存放一个字符串 abcdedgsgs 之类, 或者几行英文文本.

代码:

package helloworld;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.stream.Collectors;
 
public class Huffman {

	class HuffmanNode {

		char character;
 
		int weight;

		HuffmanNode leftChild;

		HuffmanNode rightChild;
 
		HuffmanNode parent;
 
		public HuffmanNode(char paraCharacter, int paraWeight, HuffmanNode paraLeftChild,
				HuffmanNode paraRightChild, HuffmanNode paraParent) {
			character = paraCharacter;
			weight = paraWeight;
			leftChild = paraLeftChild;
			rightChild = paraRightChild;
			parent = paraParent;
		}// Of HuffmanNode
 
		public String toString() {
			String resultString = "(" + character + ", " + weight + ")";
 
			return resultString;
		}// Of toString
 
	}// Of class HuffmanNode
 
	public static final int NUM_CHARS = 256;
 

	String inputText;
 
	int alphabetLength;
 

	char[] alphabet;

	int[] charCounts;
 
	int[] charMapping;

	String[] huffmanCodes;
 
	HuffmanNode[] nodes;
 
	public Huffman(String paraFilename) {
		charMapping = new int[NUM_CHARS];
 
		readText(paraFilename);
	}// Of the first constructor
 
	public void readText(String paraFilename) {
		try {
			inputText = Files.newBufferedReader(Paths.get(paraFilename), StandardCharsets.UTF_8)
					.lines().collect(Collectors.joining("\n"));
		} catch (Exception ee) {
			System.out.println(ee);
			System.exit(0);
		} // Of try
 
		System.out.println("The text is:\r\n" + inputText);
	}// Of readText
	public static void main(String args[]) {
		Huffman tempHuffman = new Huffman("D:/minfan/temp/huffmantext-small.txt");
	}// Of main
}

今天的代码主要是完成定义节点和读取文件部分。
关于Huffman的详细介绍

第 29 天: Huffman 编码 (建树)

今天新增的代码如下:

	public void constructAlphabet() {

		Arrays.fill(charMapping, -1);
		
		int[] tempCharCounts = new int[NUM_CHARS];
		
		int tempCharIndex;
 
		char tempChar;
		for (int i = 0; i < inputText.length(); i++) {
			tempChar = inputText.charAt(i);
			tempCharIndex = (int) tempChar;
 
			System.out.print("" + tempCharIndex + " ");
 
			tempCharCounts[tempCharIndex]++;
		} // i
		
		alphabetLength = 0;
		for (int i = 0; i < 255; i++) {
			if (tempCharCounts[i] > 0) {
				alphabetLength++;
			} //if
		} //i
 
		alphabet = new char[alphabetLength];
		charCounts = new int[2 * alphabetLength - 1];
 
		int tempCounter = 0;
		for (int i = 0; i < NUM_CHARS; i++) {
			if (tempCharCounts[i] > 0) {
				alphabet[tempCounter] = (char) i;
				charCounts[tempCounter] = tempCharCounts[i];
				charMapping[i] = tempCounter;
				tempCounter++;
			} //if
		} //i
 
		System.out.println("The alphabet is: " + Arrays.toString(alphabet));
		System.out.println("Their counts are: " + Arrays.toString(charCounts));
		System.out.println("The char mappings are: " + Arrays.toString(charMapping));
	}//constructAlphabet

	public void constructTree() {
		nodes = new HuffmanNode[alphabetLength * 2 - 1];
		boolean[] tempProcessed = new boolean[alphabetLength * 2 - 1];
 
		for (int i = 0; i < alphabetLength; i++) {
			nodes[i] = new HuffmanNode(alphabet[i], charCounts[i], null, null, null);
		} //i
 .
		int tempLeft, tempRight, tempMinimal;
		for (int i = alphabetLength; i < 2 * alphabetLength - 1; i++) {
				tempLeft = -1;
			tempMinimal = Integer.MAX_VALUE;
			for (int j = 0; j < i; j++) {
				if (tempProcessed[j]) {
					continue;
				} //if
 
				if (tempMinimal > charCounts[j]) {
					tempMinimal = charCounts[j];
					tempLeft = j;
				} //if
			} //j
			tempProcessed[tempLeft] = true;
 
			tempRight = -1;
			tempMinimal = Integer.MAX_VALUE;
			for (int j = 0; j < i; j++) {
				if (tempProcessed[j]) {
					continue;
				} //if
 
				if (tempMinimal > charCounts[j]) {
					tempMinimal = charCounts[j];
					tempRight = j;
				} //if
			} //j
			tempProcessed[tempRight] = true;
			System.out.println("Selecting " + tempLeft + " and " + tempRight);
 
			charCounts[i] = charCounts[tempLeft] + charCounts[tempRight];
			nodes[i] = new HuffmanNode('*', charCounts[i], nodes[tempLeft], nodes[tempRight], null);
 
			nodes[tempLeft].parent = nodes[i];
			nodes[tempRight].parent = nodes[i];
			System.out.println("The children of " + i + " are " + tempLeft + " and " + tempRight);
		} //i
	}//constructTree
 
	public HuffmanNode getRoot() {
		return nodes[nodes.length - 1];
	}//getRoot
	public static void main(String args[]) {
		Huffman tempHuffman = new Huffman("D:/minfan/temp/huffmantext-small.txt");
		tempHuffman.constructAlphabet();

		tempHuffman.constructTree();

		HuffmanNode tempRoot = tempHuffman.getRoot();
		System.out.println("The root is: " + tempRoot);
		System.out.println("Preorder visit:");
		tempHuffman.preOrderVisit(tempHuffman.getRoot());

	}//main

今天在昨天的基础上进行,添加了几个函数和main函数对应的内容。

第 30 天: Huffman 编码 (编码与解码)

今天新增的代码如下:

	public void preOrderVisit(HuffmanNode paraNode) {
		System.out.print("(" + paraNode.character + ", " + paraNode.weight + ") ");

		if (paraNode.leftChild != null) {
			preOrderVisit(paraNode.leftChild);
		} //if

		if (paraNode.rightChild != null) {
			preOrderVisit(paraNode.rightChild);
		} //if
	}//preOrderVisit

	public void generateCodes() {
		huffmanCodes = new String[alphabetLength];
		HuffmanNode tempNode;
		for (int i = 0; i < alphabetLength; i++) {
			tempNode = nodes[i];
			// Use tempCharCode instead of tempCode such that it is unlike
			// tempNode.
			// This is an advantage of long names.
			String tempCharCode = "";
			while (tempNode.parent != null) {
				if (tempNode == tempNode.parent.leftChild) {
					tempCharCode = "0" + tempCharCode;
				} else {
					tempCharCode = "1" + tempCharCode;
				} //if

				tempNode = tempNode.parent;
			} //while

			huffmanCodes[i] = tempCharCode;
			System.out.println("The code of " + alphabet[i] + " is " + tempCharCode);
		} //i
	}//generateCodes

	public String coding(String paraString) {
		String resultCodeString = "";

		int tempIndex;
		for (int i = 0; i < paraString.length(); i++) {
			// From the original char to the location in the alphabet.
			tempIndex = charMapping[(int) paraString.charAt(i)];

			// From the location in the alphabet to the code.
			resultCodeString += huffmanCodes[tempIndex];
		} //i
		return resultCodeString;
	}//coding

	public String decoding(String paraString) {
		String resultCodeString = "";

		HuffmanNode tempNode = getRoot();

		for (int i = 0; i < paraString.length(); i++) {
			if (paraString.charAt(i) == '0') {
				tempNode = tempNode.leftChild;
				System.out.println(tempNode);
			} else {
				tempNode = tempNode.rightChild;
				System.out.println(tempNode);
			} //if

			if (tempNode.leftChild == null) {
				System.out.println("Decode one:" + tempNode);
				// Decode one char.
				resultCodeString += tempNode.character;

				// Return to the root.
				tempNode = getRoot();
			} //if
		} //i

		return resultCodeString;
	}//decoding

今天的代码量不多,但是更需要理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值