堆栈
可以看成是有特定规则为的线性表,特定规则就是先进后出,后进先出,可以看成是我们List的先insertFromHead的要后deleteFromHead,所以利用这一点可以通过继承或组合的方式来构建堆栈。
继承构建堆栈:
public class StackInheritance extends List {
public StackInheritance() { super( "stack" ); }
public void push( Object o )
{ insertFromHead( o ); }
public Object pop() throws EmptyListException
{ return deleteFromHead(); }
public boolean isEmpty() { return super.isEmpty(); }
public void print() { super.print(); }
}
组合构建堆栈:
public class StackComposition {
private List s;
public StackComposition() { s = new List( "stack" ); }
public void push( Object o )
{ s.insertFromHead( o ); }
public Object pop() throws EmptyListException
{ return s.deleteFromHead(); }
public boolean isEmpty() { return s.isEmpty(); }
public void print() { s.print(); }
}
队列
可以看成是有特定规则为的线性表,特定规则就是先进先出(FIFO),后进后出,可以看成是我们List的先insertFromBack的要后deleteFromHead,所以利用这一点可以通过继承或组合的方式来构建堆栈。
继承构建队列
public class QueueInheritance extends List {
public QueueInheritance() { super( "queue" ); }
public void enqueue( Object o )
{ insertFromBack( o ); }
public Object dequeue()
throws EmptyListException { returnDeleteFromHead(); }
public boolean isEmpty() { return super.isEmpty(); }
public void print() { super.print(); }
}
二叉树
可以看成是一堆散节点通过特殊的连接构成的散点集,这些散点集构成了特殊的结构,看起来成了树一样的结果。
如下图所示,上面的为二叉树的逻辑结构,这样的逻辑结构利于分析二叉树的性质,却不能说明二叉树存储的实际情形,因此需要使用下图所示的二叉树的物理结构来描述其存储特性,二叉树的节点存储为线性表,线性表中的节点有自己的特殊的包含(连接关系),因此使得这种物理结构和它的逻辑结构有了能够转换的基础。
鉴于上面这张物理结构和逻辑结构,我们采用Java提供的List(LinkedList)来构建主存储结构,即Node节点的线性表以达到索引的目的。然后建立节点之间的连接关系。
import java.util.LinkedList;
import java.util.List;
public class BinTreeTraverse {
private int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
private static List<Node> nodeList = null;
/**
* 内部类:节点
*/
private static class Node {
Node leftChild;
Node rightChild;
int data;
Node(int newData) {
leftChild = null;
rightChild = null;
data = newData;
}
}
public void createBinTree() {
nodeList = new LinkedList<Node>();
// 将一个数组的值依次转换为Node节点
for (int nodeIndex = 0; nodeIndex < array.length; nodeIndex++) {
nodeList.add(new Node(array[nodeIndex]));
}
// 对前lastParentIndex-1个父节点按照父节点与孩子节点的数字关系建立二叉树
for (int parentIndex = 0; parentIndex < array.length / 2 - 1; parentIndex++) {
// 左孩子
nodeList.get(parentIndex).leftChild = nodeList
.get(parentIndex * 2 + 1);
// 右孩子
nodeList.get(parentIndex).rightChild = nodeList
.get(parentIndex * 2 + 2);
}
// 最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独拿出来处理
int lastParentIndex = array.length / 2 - 1;
// 左孩子
nodeList.get(lastParentIndex).leftChild = nodeList
.get(lastParentIndex * 2 + 1);
// 右孩子,如果数组的长度为奇数才建立右孩子
if (array.length % 2 == 1) {
nodeList.get(lastParentIndex).rightChild = nodeList
.get(lastParentIndex * 2 + 2);
}
}
/**
* 先序遍历
*
* 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已
*
* @param node
* 遍历的节点
*/
public static void preOrderTraverse(Node node) {
if (node == null)
return;
System.out.print(node.data + " ");
preOrderTraverse(node.leftChild);
preOrderTraverse(node.rightChild);
}
/**
* 中序遍历
*
* 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已
*
* @param node
* 遍历的节点
*/
public static void inOrderTraverse(Node node) {
if (node == null)
return;
inOrderTraverse(node.leftChild);
System.out.print(node.data + " ");
inOrderTraverse(node.rightChild);
}
/**
* 后序遍历
*
* 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已
*
* @param node
* 遍历的节点
*/
public static void postOrderTraverse(Node node) {
if (node == null)
return;
postOrderTraverse(node.leftChild);
postOrderTraverse(node.rightChild);
System.out.print(node.data + " ");
}
public static void main(String[] args) {
BinTreeTraverse binTree = new BinTreeTraverse();
binTree.createBinTree();
// nodeList中第0个索引处的值即为根节点
Node root = nodeList.get(0);
System.out.println("先序遍历:");
preOrderTraverse(root);
System.out.println();
System.out.println("中序遍历:");
inOrderTraverse(root);
System.out.println();
System.out.println("后序遍历:");
postOrderTraverse(root);
}
}
这里我们为什么不使用自己定义的NodeList呢?因为如果一旦使用这个NodeList来作为主存储部分,就会使得在子节点的指向过程中导致整个结构指向混乱,造成对结构的破坏。