數據結構二叉樹

一下是java語言編寫的關於數據結構中二叉樹的一些常見操作:

首先需要定義二叉樹的節點類Node,代碼如下:

/**
 * 二叉樹的節點類
 * @author xxqi1229
 *
 */
public class Node {
private Node leftChild;//左孩子
private Node rightChild;//有孩子
private int data;//該節點的值,此處用int類型的值爲例
boolean canVisit = false ;//此變量的值在後序非遞歸遍歷的時候需要用到,表示節點是否可以直接訪問

public Node(){}

public Node(int data){
leftChild = rightChild = null ;
this.data = data ;
}


public Node getLeftChild() {
return leftChild;
}


public void setLeftChild(Node leftChild) {
this.leftChild = leftChild;
}


public Node getRightChild() {
return rightChild;
}


public void setRightChild(Node rightChild) {
this.rightChild = rightChild;
}


public int getData() {
return data;
}


public void setData(int data) {
this.data = data;
}

public String toString(){
return "" + this.data ;
}


public boolean isCanVisit() {
return canVisit;
}


public void setCanVisit(boolean canVisit) {
this.canVisit = canVisit;
}
}


有了這個節點類之後,就是二叉樹的一些具體操作了,這些操作都封裝在Tree類中,Tree的代碼如下:

package edu.qc.tree;


import java.util.Stack;


/**
 * 二叉樹
 * @author Administrator
 *
 */
public class Tree {
private Node root ;//根結點
private int count  ;//節點個數
private boolean find = false ;//在查找特定節點的時候需要使用該成員變量

public Tree(){//無參構造函數
this.root = null ;
this.count = 0 ;
}

public Tree(int[] data){
count = 0 ;
root = this.createTree(root, data, 1) ;
}

/**
* 二叉樹的創建
* @param node :創建的節點
* @param data : 節點的值
* @param index : 數組的下標
* @return
*/
public Node createTree(Node node , int[] data , int index){
if(index > data.length){//數組下標越界
return null ;

if(null == node){//如果節點不存在則創建新節點,並設置節點的值。 
node = new Node(data[index-1]) ;
}else{
node.setData(data[index-1]) ;
}
count++ ;//記錄節點的數目
//遞歸的創建該節點的左孩子
Node leftNode = createTree(node.getLeftChild() , data , 2*index) ;
//遞歸的創建該節點的右孩子
Node rightNode = createTree(node.getRightChild() , data , 2*index+1) ;
//設置當前節點的左孩子和有孩子
node.setLeftChild(leftNode) ;
node.setRightChild(rightNode) ;
return node ;//返回當前創建的節點
}

/**
* 後序遍歷遞歸算法
* @param node
*/
public void postList(Node node){
if(node != null){
postList(node.getLeftChild()) ;//遍歷左孩子
postList(node.getRightChild()) ;//遍歷有孩子
System.out.print(node.getData() + ",");//輸出當前節點的s值
}
}

/**
* 後序遍歷非遞歸算法
* @param node
*/
public void postList2(Node node){
Stack<Node> stack = new Stack<Node>() ;
while(node != null || !stack.isEmpty()){//節點不爲空或者棧部位空時進入循環
if(node != null){//將根節點的所有左孩子入棧
stack.push(node) ;
node = node.getLeftChild() ;
}else{
//如果棧頂節點可以訪問,canVisit默認爲false,不能訪問,只有在有孩子也遍歷了之後纔可以訪問父親節點
if(stack.lastElement().isCanVisit()){
System.out.print(stack.pop().getData() + ",");//出棧,輸出結果
}else{//如果棧頂節點不能訪問,則遍歷節點的有孩子,並設置節點可以訪問
node = stack.lastElement().getRightChild() ;//遍歷有孩子
stack.lastElement().setCanVisit(true) ;//將父節點設置爲可以訪問
}
}
}
}

/**
* 層次遍歷
* @param node
*/
public void levelList(Node node){
Node temp = null ;
List<Node> queue = new ArrayList<Node>() ;
queue.add(node) ;
while(!queue.isEmpty()){
temp = queue.remove(0) ;
System.out.print(temp.getData() + ",");
if(temp.getLeftChild() != null){
queue.add(temp.getLeftChild()) ;
}
if(temp.getRightChild() != null){
queue.add(temp.getRightChild()) ;
}
}
}

/**
* 查找值data1和data2的第一個祖先節點,返回第一個祖先節點.此處定義了兩個棧作爲輔助,需要遍歷兩次二叉樹。程序可以大量優化。
* @param root : 從root開始查找
* @param data1 : 值爲data1的節點
* @param data2 : 值爲data2的節點
* @return
*/
public Node findNode(Node root , int data1 , int data2) {
Stack<Node> s1 = new Stack<Node>() ;//存放data1的祖先節點
Stack<Node> s2 = new Stack<Node>() ;//存放data2的祖先節點

findParents(s1 , root , data1) ;//將data1的所有祖先節點存放在s1中
this.find = false ;
findParents(s2 , root , data2) ;//將data2的所有祖先節點存放在s2中

Node parent = null ;
while(s1.size()>0 && s2.size()>0 ){//查找第一個祖先節點
if(s1.get(0).getData() == s2.get(0).getData()){
parent = s1.remove(0) ;
s2.remove(0) ;
}else{
break ;
}
}

return parent ;//返回第一個祖先節點 
}

/**
* 從root開始查找值爲data1的所有祖先節點,並將祖先節點存放在s中
* @param s : 存放祖先節點的棧
* @param root : 開始尋找的及誒單
* @param data : 尋找節點的值
* @return : 是否找到值爲data1的節點
*/
public boolean findParents(Stack<Node> s , Node root , int data){
if(root != null && !find){
s.push(root) ;//根節點入棧
if(data == root.getData()){
find = true ;//找到了節點
}else{
if(root.getLeftChild() != null){
findParents(s , root.getLeftChild() , data) ;//如果左邊找到了
}

if(root.getRightChild() != null){
findParents(s, root.getRightChild() , data) ;
}

if(!find){//如果當前節點的左孩子和有孩子中都沒有找到要查找的節點,則當前節點出棧。
s.pop() ;
}
}
}
return find;
}

/**
* 中序遍歷遞歸算法
* @param node
*/
public void midList(Node node){
if(node != null){
midList(node.getLeftChild()) ;
System.out.print(node.getData() + ",");
midList(node.getRightChild()) ;
}
}

/**
* 中序遍歷非遞歸算法
* @param node
*/
public void midList2(Node node){
Stack<Node> stack = new Stack<Node>() ;
while(node != null || !stack.isEmpty()){
if(node != null){
stack.push(node) ;
node = node.getLeftChild() ;
}else{
node = stack.pop() ;
System.out.print(node.getData() + ",");
node = node.getRightChild() ;
}
}
}

/**
* 先序遍歷遞歸算法
* @param node
*/
public void preList(Node node){
if(node != null){
System.out.print(node.getData() + ",");
preList(node.getLeftChild()) ;
preList(node.getRightChild()) ;
}
}

/**
* 線序遍歷的非遞歸實現
* @param node
*/
public void preList2(Node p){
Stack<Node> stack = new Stack<Node>() ;
while(p != null || !stack.isEmpty()){
if(p != null){
System.out.print(p.getData() + ",") ;//輸出節點的值
stack.push(p) ;       //把根節點入棧
p = p.getLeftChild() ;//尋找左孩子
}else{
p = stack.pop().getRightChild() ;
}
}
}


/**
* 層次遍歷
* @param node
*/
public void levelList(Node node){
Node temp = null ;
List<Node> queue = new ArrayList<Node>() ;
queue.add(node) ;
while(!queue.isEmpty()){
temp = queue.remove(0) ;
System.out.print(temp.getData() + ",");
if(temp.getLeftChild() != null){
queue.add(temp.getLeftChild()) ;
}
if(temp.getRightChild() != null){
queue.add(temp.getRightChild()) ;
}
}
}

/**
* 求二叉樹的深度
* @param root
* @return
*/
public int getDepth(Node root){
if(null == root){
return 0 ;
}else if((null==root.getLeftChild())&&(null==root.getRightChild())){
return 1 ;
}else{
return Math.max(getDepth(root.getLeftChild()), 
       getDepth(root.getRightChild())) + 1 ;
}
}


/**
* 從節點root中查找值爲data的所有祖先節點,祖先節點存放在stack棧中。
* @param root
* @param data
* @return
*/
public boolean findNode(Node root , int data , Stack<Node> stack){
if(null == root){
return false ;
}else{
if(root.getData() == data){
return true ;
}else{
stack.push(root) ;
if(findNode(root.getLeftChild() , data , stack)){
return true ;
}
if(findNode(root.getRightChild() , data , stack)){
return true ;
}
stack.pop() ;
return false ;
}
}
}

public Node getRoot() {
return root;
}


public void setRoot(Node root) {
this.root = root;
}


public int getCount() {
return count;
}


public void setCount(int count) {
this.count = count;
}
}

這裏主要實現了二叉樹的先序、中序、後序遍歷的遞歸算法和非遞歸算法。對二叉樹的深度和層次遍歷沒有實現,希望看了此文章的朋友們可以自己實現!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章