java树算法_Java数据结构算法(三)树
本文旨作于收集整理使用!!
導(dǎo)航
一、樹(shù)
樹(shù)(Tree)是n(n≥0)個(gè)結(jié)點(diǎn)的有限集,n=0稱之為空樹(shù)。在非空樹(shù)種:當(dāng)有且僅有一個(gè)特定的稱為根(Root)的結(jié)點(diǎn); 其余結(jié)點(diǎn)可以劃分為m(m>0)個(gè)互不相交的有限集T1、T2 、…、Tm,每個(gè)集Ti(1≤i≤m)均為樹(shù),且稱為樹(shù)的子樹(shù)(SubTree), 如下圖所示。
根節(jié)點(diǎn):根節(jié)點(diǎn)指沒(méi)有雙親結(jié)點(diǎn)的結(jié)點(diǎn),一棵樹(shù)中最多有一個(gè)根節(jié)點(diǎn)(如A)
葉子結(jié)點(diǎn):沒(méi)有孩子結(jié)點(diǎn)的結(jié)點(diǎn)叫作葉子結(jié)點(diǎn)(如L、M、F)
兄弟結(jié)點(diǎn):擁有相同雙親結(jié)點(diǎn)的所有孩子結(jié)點(diǎn)叫作兄弟結(jié)點(diǎn)(L、M是E的兄弟結(jié)點(diǎn),I、J、K是D的兄弟結(jié)點(diǎn))
結(jié)點(diǎn)的深度:是指從根節(jié)點(diǎn)到該節(jié)點(diǎn)的路徑長(zhǎng)度(O點(diǎn)的深度為3,A—C—G—O)
樹(shù)的高度:是樹(shù)中所有結(jié)點(diǎn)高度的最大值,樹(shù)的深度是樹(shù)中所有結(jié)點(diǎn)深度的最大值,對(duì)于同一棵樹(shù),其深度和高度是相同的,但是對(duì)于各個(gè)結(jié)點(diǎn),其深度和高度不一定相同
二、二叉樹(shù)
二叉樹(shù)(Binary Tree)是n(n>=0)個(gè)節(jié)點(diǎn)的有限集合,該集合或?yàn)榭占?#xff0c;或?yàn)橛梢粋€(gè)根節(jié)點(diǎn)和兩顆互不相交的,分別稱為根節(jié)點(diǎn)的左子樹(shù)和右子樹(shù)的二叉樹(shù)組成。
二叉樹(shù)
所有節(jié)點(diǎn)只有左子樹(shù)的二叉樹(shù)稱為左斜樹(shù),只有右子樹(shù)的二叉樹(shù)稱為右斜樹(shù)。
所有節(jié)點(diǎn)均含左子樹(shù)和右子樹(shù),這樣的二叉樹(shù)稱為滿二叉樹(shù)。
滿二叉樹(shù)
完全二叉樹(shù):若設(shè)二叉樹(shù)的深度為h,除第 h 層外,其它各層 (1~h-1) 的結(jié)點(diǎn)數(shù)都達(dá)到最大個(gè)數(shù),第 h 層所有的結(jié)點(diǎn)都連續(xù)集中在最左邊,這就是完全二叉樹(shù)。
完全二叉樹(shù)
二叉樹(shù)的應(yīng)用:編譯器中的表達(dá)式樹(shù)、用于數(shù)據(jù)壓縮算法中的赫夫曼編碼樹(shù)、支持在集合中查找、插入和刪除,其平均時(shí)間復(fù)雜度為O(lognn)的二叉搜索樹(shù)(BST)、優(yōu)先隊(duì)列(PQ),它支持以對(duì)數(shù)時(shí)間(最壞情況下)對(duì)集合中的最小(或最大)數(shù)據(jù)元素進(jìn)行搜索和刪除;
1、二叉樹(shù)的存儲(chǔ)結(jié)構(gòu)
基本了解了二叉樹(shù)的組成后,我們學(xué)習(xí)怎么樣去存儲(chǔ)二叉樹(shù),了解二叉樹(shù)的存儲(chǔ)結(jié)構(gòu)。
1.1、滿二叉樹(shù)
存儲(chǔ)滿二叉樹(shù)可以使用數(shù)組,我們將上圖中的滿二叉樹(shù)存儲(chǔ)為數(shù)組為[A,B,C,D,E,F,G]),當(dāng)然我們通過(guò)數(shù)組復(fù)原二叉樹(shù)時(shí)也可以按照順序復(fù)原二叉樹(shù)。
1.2、完全二叉樹(shù)
完全二叉樹(shù)和滿二叉樹(shù)的存儲(chǔ)方法相同,上圖中的完全二叉樹(shù)轉(zhuǎn)換為數(shù)組([A,B,C,D,E,F,G,H,I])(圖中最后的H為I)。
1.2、其他二叉樹(shù)
有的二叉樹(shù)既不是滿二叉樹(shù)又不是完全二叉樹(shù)該如何存儲(chǔ)?我們可以將缺少的二叉樹(shù)的葉子節(jié)點(diǎn)用一些特殊的符號(hào)存儲(chǔ),將其轉(zhuǎn)換為完全二叉樹(shù),如下圖所示。
則如上圖中的二叉樹(shù)轉(zhuǎn)換為數(shù)組([A,B,C,D,E,F,G,#.#,H,#,#,#,I,J])
2二叉樹(shù)的遍歷
二叉樹(shù)的遍歷分為前序遍歷、中序遍歷和后序遍歷
3.1 前序遍歷
先遍歷左子樹(shù),再遍歷右子樹(shù)
2.2、 中序遍歷
從根結(jié)點(diǎn)開(kāi)始(注意并不是先訪問(wèn)根結(jié)點(diǎn)),中序遍歷根結(jié)點(diǎn)的左子樹(shù),然后是訪問(wèn)根結(jié)點(diǎn),最后中序遍歷右子樹(shù)
2.3 后序遍歷
從左到右先葉子后結(jié)點(diǎn)的方式遍歷訪問(wèn)左右子樹(shù),最后是訪問(wèn)根結(jié)點(diǎn)
3、實(shí)現(xiàn)二叉樹(shù)
如下,需要構(gòu)建如下二叉樹(shù),并實(shí)現(xiàn)其三種遍歷方法
/**
* 構(gòu)造如下二叉樹(shù)
* A
* B C
* D E G
*
*/
import java.util.List;
/**
* 構(gòu)造如下二叉樹(shù)
* A
* B C
* D E G
*/
public class BinaryTree {
TreeNode root = null;
public BinaryTree() {
root = new TreeNode(0, "A");
}
/**
* 傳統(tǒng)方法構(gòu)造二叉樹(shù)
*/
public void createBinaryTree() {
TreeNode nodeB = new TreeNode(2, "B");
TreeNode nodeC = new TreeNode(3, "C");
TreeNode nodeD = new TreeNode(4, "D");
TreeNode nodeE = new TreeNode(5, "E");
TreeNode nodeF = new TreeNode(6, "F");
root.leftChild = nodeB;
root.rightChild = nodeC;
nodeB.leftChild = nodeD;
nodeB.rightChild = nodeE;
nodeC.rightChild = nodeF;
}
/**
* 出入二叉樹(shù)的數(shù)組,創(chuàng)建二叉樹(shù)
*
* @param size 二叉樹(shù)所有節(jié)點(diǎn)的數(shù)量和
* @param datas 二叉樹(shù)的List集合
* @return 返回創(chuàng)建的節(jié)點(diǎn)
*/
public TreeNode createBinerTree(int size, List datas) {
TreeNode node = null;
if (datas.size() == 0) {
return null;
}
String data = datas.get(0);
if ("#".equals(data)) {
datas.remove(0);
return node;
}
int index = size - datas.size();
node = new TreeNode(index, data);
if (index == 0) {
root = node;
}
datas.remove(0);
node.leftChild = createBinerTree(size, datas);
node.rightChild = createBinerTree(size, datas);
return node;
}
/**
* 前序遍歷
*/
public void preOrder(TreeNode node) {
if (node == null) {
return;
} else {
System.out.println("preOrder data:" + node.getData());
preOrder(node.leftChild);
preOrder(node.rightChild);
}
}
/**
* 中序遍歷
*/
public void midOrder(TreeNode node) {
if (node == null) {
return;
} else {
midOrder(node.leftChild);
System.out.println("midOrder data:" + node.getData());
midOrder(node.rightChild);
}
}
/**
* 后序遍歷
*/
public void postOrder(TreeNode node) {
if (node == null) {
return;
} else {
preOrder(node.leftChild);
preOrder(node.rightChild);
System.out.println("postOrder data:" + node.getData());
}
}
class TreeNode {
private int index;
private String data;
private TreeNode leftChild;
private TreeNode rightChild;
public TreeNode(int index, String data) {
this.index = index;
this.data = data;
}
public TreeNode getLeftChild() {
return leftChild;
}
public void setLeftChild(TreeNode leftChild) {
this.leftChild = leftChild;
}
public TreeNode getRightChild() {
return rightChild;
}
public void setRightChild(TreeNode rightChild) {
this.rightChild = rightChild;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
}
傳入數(shù)組測(cè)試
public class test {
public static void main(String[] args) {
BinaryTree binaryTree=new BinaryTree();
String data[]={"A","B","C","D","E","#","F"};
ArrayListdatas=new ArrayList<>(Arrays.asList(data));
binaryTree.createBinerTree(datas.size(), datas);
binaryTree.preOrder(binaryTree.root);
}
}
結(jié)果
preOrder data:A
preOrder data:B
preOrder data:C
preOrder data:D
preOrder data:E
preOrder data:F
三、搜索二叉樹(shù)
二叉查找樹(shù)(又:二叉搜索樹(shù),二叉排序樹(shù)),它或者是一棵空樹(shù),或者是具有下列性質(zhì)的二叉樹(shù): 若它的左子樹(shù)不空,則左子樹(shù)上所有結(jié)點(diǎn)的值均小于它的根結(jié)點(diǎn)的值; 若它的右子樹(shù)不空,則右子樹(shù)上所有結(jié)點(diǎn)的值均大于它的根結(jié)點(diǎn)的值; 它的左、右子樹(shù)也分別為二叉排序樹(shù)。二叉排序樹(shù)的查找過(guò)程和次優(yōu)二叉樹(shù)類似,通常采取二叉鏈表作為二叉排序樹(shù)的存儲(chǔ)結(jié)構(gòu)中序遍歷二叉排序樹(shù)可得到一個(gè)關(guān)鍵字的有序序列,一個(gè)無(wú)序序列可以通過(guò)構(gòu)造一棵二叉排序樹(shù)變成一個(gè)有序序列,構(gòu)造樹(shù)的過(guò)程即為對(duì)無(wú)序序列進(jìn)行排序的過(guò)程。每次插入的新的結(jié)點(diǎn)都是二叉排序樹(shù)上新的葉子結(jié)點(diǎn),在進(jìn)行插入操作時(shí),不必移動(dòng)其它結(jié)點(diǎn),只需改動(dòng)某個(gè)結(jié)點(diǎn)的指針,由空變?yōu)榉强占纯?/p>
1、搜索二叉樹(shù)的實(shí)現(xiàn)
/**
* Author: Active_Loser
* Date: 2018/7/30 23:17
* Content: 實(shí)現(xiàn)搜索二叉樹(shù)的建立、添加、刪除等操作
*/
public class SearchBinryTree {
public TreeNode root;
public TreeNode put(int data) {
TreeNode node;
TreeNode parent = null;
if (root == null) {
node = new TreeNode(data);
root = node;
return node;
}
node = root;
while (node != null) {
parent = node;
if (data > parent.data) {
node = parent.rightChild;
} else if (data < parent.data) {
node = parent.leftChild;
} else {
return node;
}
}
node = new TreeNode(data);
if (data < parent.data) {
parent.leftChild = node;
node.parent = parent;
} else if (data > parent.data) {
parent.rightChild = node;
node.parent = parent;
}
return node;
}
public TreeNode search(int value) {
TreeNode node = root;
while (node != null && node.data != value) {
if (node.data > value) {
node = node.rightChild;
} else if (node.data < value) {
node = node.leftChild;
}
}
return node;
}
/**
* @param value 刪除的數(shù)值
* @return 返回刪除的節(jié)點(diǎn)
*/
public TreeNode delete(int value) {
//判斷是否包含需要?jiǎng)h除的數(shù)
TreeNode deleteNode = search(value);
if (null == deleteNode) {
return null;
}else {
delete(deleteNode);
}
}
private void delete(TreeNode node) {
if (node==null){
return null;
}
TreeNode parent=node.parent;
//做節(jié)點(diǎn)與有節(jié)點(diǎn)皆為NULL
if (node.leftChild==null&&node.rightChild==null){
if (parent.leftChild==node){
parent.leftChild=null;
}else {
parent.rightChild=null;
}
return;
}
//有左節(jié)點(diǎn)沒(méi)有右節(jié)點(diǎn)1.父節(jié)點(diǎn)的左節(jié)點(diǎn)2.父節(jié)點(diǎn)的右節(jié)點(diǎn)
if (node.leftChild!=null&&node.rightChild==null){
if (parent.leftChild==node){
parent.leftChild=node.leftChild;
}else if (parent.rightChild==node){
parent.rightChild=node.leftChild;
}
return;
}
//有右節(jié)點(diǎn)沒(méi)有左節(jié)點(diǎn)1.父節(jié)點(diǎn)的左節(jié)點(diǎn)2.父節(jié)點(diǎn)的右節(jié)點(diǎn)
if (node.leftChild!=null&&node.rightChild==null){
if (parent.leftChild==node){
parent.leftChild=node.rightChild;
}else if (parent.rightChild==node){
parent.rightChild=node.rightChild;
}
return;
}
//既有左節(jié)點(diǎn)也有右節(jié)點(diǎn)
//獲取刪除節(jié)點(diǎn)的后繼節(jié)點(diǎn)
TreeNode next=getNextNode(node);
delete(next);
node.data=next.data;
}
private TreeNode getNextNode(TreeNode node) {
if (node==null){
return null;
}else {
if (node.rightChild!=null){
return getMinTreeNode(node.rightChild);
}else {
TreeNode parent=node.parent;
while (parent!=null&&node==parent.rightChild){
node=parent;
parent=parent.parent;
}
return parent;
}
}
return null;
}
//右子樹(shù)最小值,左子樹(shù)最大值
public TreeNode getMinTreeNode(TreeNode node){
if (node==null){
return null;
}else {
while (node.leftChild !=null){
node=node.leftChild;
}
}
return node;
}
public void midOrder(TreeNode node) {
if (node == null) {
return;
} else {
midOrder(node.leftChild);
System.out.println("midOrder:" + node.data);
midOrder(node.rightChild);
}
}
class TreeNode {
private TreeNode leftChild;
private TreeNode rightChild;
private TreeNode parent;
private int data;
public TreeNode(int data) {
this.data = data;
}
public TreeNode getLeftChild() {
return leftChild;
}
public void setLeftChild(TreeNode leftChild) {
this.leftChild = leftChild;
}
public TreeNode getRightChild() {
return rightChild;
}
public void setRightChild(TreeNode rightChild) {
this.rightChild = rightChild;
}
public TreeNode getParent() {
return parent;
}
public void setParent(TreeNode parent) {
this.parent = parent;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
}
總結(jié)
以上是生活随笔為你收集整理的java树算法_Java数据结构算法(三)树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 《世纪之石》图文流程攻略教学篇(1)
- 下一篇: java 并发 面试题_阿里面试官总结1