使用具有通用性的队列
前言
今天的这段代码初看与昨天的很相似,准确来说,所实现的功能确实都是一样的,但是今天的代码中传递了一个重要的编程思想–类复用(代码复用)。
一、Object类简介
Object类是Javajava.lang
包下的核心类,Object类是所有类的父类,任何一个类如果没有明确的继承一个父类的话,那么它就是Object的子类。例如
public class CircleObjectQueue;
等价于
public class CircleObjectQueue extends Object;
二、 关于Integer
Java 本身将 int, double, char 分别封装到 Integer, Double, Char 类.
Integer类和int区别:
- Integer 是 int 包装类,final修饰,int 是八大基本数据类型之一(byte,char,short,int,long,float,double,boolean)
- Integer 是类,默认值为null,int是基本数据类型,默认值为0;
- Integer 表示的是对象,用一个引用指向这个对象,而int是基本数据类型,直接存储数值。
Integer tempIndexInteger = Integer.valueOf(0);
上面代码是将字串"0"的类型转换为integer。
三、代码实现
与昨天的代码一样,用getNumNodes()函数获取二叉树的节点数,因为要把各个节点存入队列,所以队列长度就为节点数:
int tempLength = getNumNodes();
。
使用char[tempLength]创建数组,把新创建的数组的引用复制给变量valuesArray与indicesArray:
valuesArray = new char[tempLength];
indicesArray = new int[tempLength];
创建一个存放二叉树节点Value的队列,一个存放节点索引的队列。tempIntQueue队列创建与昨天的代码中不同,昨天使用的队列有两种:存储二叉树节点的队列;存储整数的队列。今天将利用代码的复用性,用一个存储对象的队列实现昨天两个队列完成的功能。
存储对象的队列, 实际上是存储对象的地址 (引用、指针). 因此, 可以存储任何类的对象 (的引用).代码如下:
// Traverse and convert at the same time.
CircleObjectQueue tempQueue = new CircleObjectQueue();
tempQueue.enqueue(this);
CircleObjectQueue tempIntQueue = new CircleObjectQueue();
Integer tempIndexInteger = Integer.valueOf(0);
tempIntQueue.enqueue(tempIndexInteger);
这里还有个没有明白的地方就是tempQueue.enqueue(this)
中的this,参考前后代码可知,这里的this应该指的是二叉树节点存储的对象。但是不明白为什么这个地方可以用this。
四、代码与数据测试
package datastructure.tree;
import java.util.Arrays;
import datastructure.queue.*;
/**
* Binary tree with char type elements.
*
* @auther Weijie Pu weijiepu@163.com.
*/
public class BinaryCharTree {
/**
* The value in char.
*/
char value;
/**
* The left child.
*/
BinaryCharTree leftChild;
/**
* The right child.
*/
BinaryCharTree rightChild;
/**
*********************
* The first constructor.
*
* @param paraName
* The value.
*********************
*/
public BinaryCharTree(char paraName) {
value = paraName;
leftChild = null;
rightChild = null;
} // Of the constructor
/**
********************
* Mannually construct a tree. Only for testing.
********************
*/
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;
} // Of maualConstructTree
/**
********************
* Pre-order visit.
********************
*/
public void preOrderVisit() {
System.out.print("" + value + " ");
if (leftChild != null) {
leftChild.preOrderVisit();
} // Of if
if (rightChild != null) {
rightChild.preOrderVisit();
} // Of if
} // Of preOrderVisit
/**
********************
* In-order visit.
********************
*/
public void inOrderVisit() {
if (leftChild != null) {
leftChild.inOrderVisit();
} // Of if
System.out.print("" + value + " ");
if (rightChild != null) {
rightChild.inOrderVisit();
} // Of if
} // Of inOrderVisit
/**
********************
* Post-order visit.
********************
*/
public void postOrderVisit() {
if (leftChild != null) {
leftChild.postOrderVisit();
} // Of if
if (rightChild != null) {
rightChild.postOrderVisit();
} // Of if
System.out.print("" + value + " ");
} // Of postOrderVisit
/**
********************
* Get the depth of the binary tree.
*
* @return The depth. It is 1 if there is only one node. i.e., the root.
********************
*/
public int getDepth() {
// It is a leaf.
if ((leftChild == null) && (rightChild == null)) {
return 1;
} // Of if
// The depth of the left child.
int tempLeftDepth = 0;
if (leftChild != null) {
tempLeftDepth = leftChild.getDepth();
} // Of if
// The depth of the right child.
int tempRightDepth = 0;
if (rightChild != null) {
tempRightDepth = rightChild.getDepth();
} // Of if
// The depth should increment by 1.
if (tempLeftDepth >= tempRightDepth) {
return tempLeftDepth + 1;
} else {
return tempRightDepth + 1;
} // Of if
} // Of getDepth
/**
********************
* Get the number of nodes.
*
* @return The number of nodes.
********************
*/
public int getNumNodes() {
// It is a leaf.
if ((leftChild == null) && (rightChild == null)) {
return 1;
} // Of if
// The number of nodes of the left child.
int tempLeftNodes = 0;
if (leftChild != null) {
tempLeftNodes = leftChild.getNumNodes();
} // Of if
// The number of nodes of the right child.
int tempRightNodes = 0;
if (rightChild != null) {
tempRightNodes = rightChild.getNumNodes();
} // Of if
// The total number of nodes.
return tempLeftNodes + tempRightNodes + 1;
}
/**
* The values of nodes according to breadth first traversal.
*/
char[] valuesArray;
/**
* The indices in the complete binary tree.
*/
int[] indicesArray;
/**
********************
* Convert the tree to data arrays, including a char array and an int array.
* The results are stored in two member variables.
*
* @see #valuesArray
* @see #indicesArray
*********************
*/
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);
} // Of if
if (tempTree.rightChild != null) {
tempQueue.enqueue(tempTree.rightChild);
tempIntQueue.enqueue(tempIndex * 2 + 2);
} // Of if
tempTree = (BinaryCharTree) tempQueue.dequeue();
tempIndex = tempIntQueue.dequeue();
} // Of while
}// Of toDataArrays
/**
********************
* Convert the tree to data arrays, including a char array and an int array.
* The results are stored in two member variables.
*
* @see #valuesArray
* @see #indicesArray
********************
*/
public void toDataArraysObjectQueue() {
// Initialize arrays.
int tempLength = getNumNodes();
valuesArray = new char[tempLength];
indicesArray = new int[tempLength];
int i = 0;
// Traverse an convert at the same time.
CircleObjectQueue tempQueue = new CircleObjectQueue();
tempQueue.enqueue(this);
CircleObjectQueue tempIntQueue = new CircleObjectQueue();
Integer tempIndexInteger = Integer.valueOf(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(Integer.valueOf(tempIndex * 2 + 1));
} // Of if
if (tempTree.rightChild != null) {
tempQueue.enqueue(tempTree.rightChild);
tempIntQueue.enqueue(Integer.valueOf(tempIndex * 2 + 2));
} // Of if
tempTree = (BinaryCharTree) tempQueue.dequeue();
if (tempTree == null) {
break;
} // Of if
tempIndex = ((Integer) tempIntQueue.dequeue()).intValue();
} // Of while
} // Of toDataArraysObjectQueue
/**
********************
* The entrance of the program.
*
* @param args
* Not used now.
********************
*/
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));
} // Of main
} // Of BinaryCharTree
运行结果:
总结
个人感觉这两天的代码难度一下子上去了,之前的代码都是写的时间大于思考的时间,现在是思考的时间远大于写代码的时间。在学习数据结构时,二叉树便是一个不可忽视的重点,但更多的是学会相关的算法,一到存储这一块就不行了,特别是顺序存储结构,到链式存储应该会好一点,毕竟树的链式存储也会更形象一点。