java tree类子项的添加和删除_使用Java实现二叉树的添加,删除,获取以及遍历...
二叉樹(shù)節(jié)點(diǎn)的聲明:
static final class Entry>{
//保存的數(shù)據(jù)
private T item;
//左子樹(shù)
private Entry left;
//右子樹(shù)
private Entry right;
//父節(jié)點(diǎn)
private Entry parent;
Entry(T item,Entry parent){
this.item = item;
this.parent = parent;
}
}
類(lèi)屬性:
//根節(jié)點(diǎn)
private Entry root;
//數(shù)據(jù)量
private int size = 0;
二叉樹(shù)添加數(shù)據(jù):
/**
* 添加元素
* @param item 待添加元素
* @return 已添加元素
*/
public T put(T item){
//每次添加數(shù)據(jù)的時(shí)候都是從根節(jié)點(diǎn)向下遍歷
Entry t = root;
if (t == null){
//當(dāng)前的叉樹(shù)樹(shù)的為空,將新節(jié)點(diǎn)設(shè)置為根節(jié)點(diǎn),父節(jié)點(diǎn)為null
root = new Entry<>(item,null);
size++;
return root.item;
}
//自然排序結(jié)果,如果傳入的數(shù)據(jù)小于當(dāng)前節(jié)點(diǎn)返回-1,大于當(dāng)前節(jié)點(diǎn)返回1,否則返回0
int ret = 0;
//記錄父節(jié)點(diǎn)
Entry p = t;
while (t != null){
//與當(dāng)前節(jié)點(diǎn)比較
ret = item.compareTo(t.item);
p = t;
//插入節(jié)點(diǎn)比當(dāng)前節(jié)點(diǎn)小,把當(dāng)前節(jié)點(diǎn)設(shè)置為左子節(jié)點(diǎn),然后與左子比較,以此類(lèi)推找到合適的位置
if (ret < 0)
t = t.left;
//大于當(dāng)前節(jié)點(diǎn)
else if (ret > 0)
t = t.right;
else {
//相等就把舊值覆蓋掉
t.item = item;
return t.item;
}
}
//創(chuàng)建新節(jié)點(diǎn)
Entry e = new Entry<>(item,p);
//根據(jù)比較結(jié)果將新節(jié)點(diǎn)放入合適的位置
if (ret < 0)
p.left = e;
else
p.right = e;
size++;
return e.item;
}
在put的過(guò)程中,使用Comparable中的compareTo來(lái)比較兩個(gè)元素的大小的,所以在二叉樹(shù)中存儲(chǔ)的元素必須要繼承Comparable 類(lèi),覆寫(xiě)compareTo方法。
二叉樹(shù)刪除數(shù)據(jù)
/**
* 刪除元素
* 刪除元素如果細(xì)分的話,可以分為4中:沒(méi)有子節(jié)點(diǎn),只有左節(jié)點(diǎn),只有右節(jié)點(diǎn),有兩個(gè)子節(jié)點(diǎn)
* 1)沒(méi)有子節(jié)點(diǎn)這種情況比較簡(jiǎn)單,直接刪除就可以了
* 2)只有左節(jié)點(diǎn)或右節(jié)點(diǎn),這兩種情況處理方式是一致的,只是方向相反,所以在一起講了,
* 將刪除節(jié)點(diǎn)的父節(jié)點(diǎn)的左節(jié)點(diǎn)(右節(jié)點(diǎn))指向刪除節(jié)點(diǎn)的子節(jié)點(diǎn),將左節(jié)點(diǎn)(右節(jié)點(diǎn))指向刪除節(jié)點(diǎn)的父節(jié)點(diǎn)
* 3)有兩個(gè)子節(jié)點(diǎn),這種情況相對(duì)來(lái)說(shuō)比較復(fù)雜一點(diǎn):
* 找到刪除節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)或后繼節(jié)點(diǎn),然后將前驅(qū)或后繼節(jié)點(diǎn)的值賦給刪除節(jié)點(diǎn),然后將前驅(qū)或后繼節(jié)點(diǎn)刪除。本質(zhì)是刪除前驅(qū)或后繼節(jié)點(diǎn)
* 前驅(qū)節(jié)點(diǎn)的特點(diǎn):
* 1)刪除的左子節(jié)點(diǎn)沒(méi)有右子節(jié)點(diǎn),那么左子節(jié)點(diǎn)即為前驅(qū)節(jié)點(diǎn)
* 2)刪除節(jié)點(diǎn)的左子節(jié)點(diǎn)有右子節(jié)點(diǎn),那么最右邊的最后一個(gè)節(jié)點(diǎn)即為前驅(qū)節(jié)點(diǎn)
* 后繼節(jié)點(diǎn)的特點(diǎn):
* 與前驅(qū)節(jié)點(diǎn)剛好相反,總是右子節(jié)點(diǎn),或則右子節(jié)點(diǎn)的最左子節(jié)點(diǎn);例如:刪除節(jié)點(diǎn)為c ,那么前驅(qū)節(jié)點(diǎn)為 m,后繼節(jié)點(diǎn)為n
* a
* / \
* b c
* / \ / \
* d e f g
* / \ / \ / \ / \
* @param item 刪除元素 h i j k l m n o
* @return 刪除結(jié)果
*/
public boolean remove(T item){
//獲取刪除節(jié)點(diǎn)
Entry delEntry = getEntry(item);
if (delEntry == null) return false;
//刪除節(jié)點(diǎn)的父節(jié)點(diǎn)
Entry p = delEntry.parent;
size--;
//情況1:沒(méi)有子節(jié)點(diǎn)
if (delEntry.left == null && delEntry.right == null){
//刪除節(jié)點(diǎn)為根節(jié)點(diǎn)
if (delEntry == root){
root = null;
}else {//非根節(jié)點(diǎn)
//刪除的是父節(jié)點(diǎn)的左節(jié)點(diǎn)
if (delEntry == p.left){
p.left = null;
}else {//刪除右節(jié)點(diǎn)
p.right = null;
}
}
//情況2:刪除的節(jié)點(diǎn)只有左節(jié)點(diǎn)
}else if (delEntry.right == null){
Entry lc = delEntry.left;
//刪除的節(jié)點(diǎn)為根節(jié)點(diǎn),將刪除節(jié)點(diǎn)的左節(jié)點(diǎn)設(shè)置成根節(jié)點(diǎn)
if (p == null) {
lc.parent = null;
root = lc;
} else {//非根節(jié)點(diǎn)
if (delEntry == p.left){//刪除左節(jié)點(diǎn)
p.left = lc;
}else {//刪除右節(jié)點(diǎn)
p.right = lc;
}
lc.parent = p;
}
//情況3:刪除節(jié)點(diǎn)只有右節(jié)點(diǎn)
}else if (delEntry.left == null){
Entry rc = delEntry.right;
//刪除根節(jié)點(diǎn)
if (p == null) {
rc.parent = null;
root = rc;
}else {//刪除非根節(jié)點(diǎn)
if (delEntry == p.left)
p.left = rc;
else
p.right = rc;
rc.parent = p;
}
//情況4:刪除節(jié)點(diǎn)有兩個(gè)子節(jié)點(diǎn)
}else {//有兩個(gè)節(jié)點(diǎn),找到后繼節(jié)點(diǎn),將值賦給刪除節(jié)點(diǎn),然后將后繼節(jié)點(diǎn)刪除掉即可
Entry successor = successor(delEntry);//獲取到后繼節(jié)點(diǎn)
delEntry.item = successor.item;
//后繼節(jié)點(diǎn)為右子節(jié)點(diǎn)
if (delEntry.right == successor){
//右子節(jié)點(diǎn)有右子節(jié)點(diǎn)
if (successor.right != null) {
delEntry.right = successor.right;
successor.right.parent = delEntry;
}else {//右子節(jié)點(diǎn)沒(méi)有子節(jié)點(diǎn)
delEntry.right = null;
}
}else {//后繼節(jié)點(diǎn)必定是左節(jié)點(diǎn)
successor.parent.left = null;
}
return true;
}
//讓gc回收
delEntry.parent = null;
delEntry.left = null;
delEntry.right = null;
return true;
}
/**
* 獲取節(jié)點(diǎn)節(jié)點(diǎn)
* @param item 獲取節(jié)點(diǎn)
* @return 獲取到的節(jié)點(diǎn),可能為null
*/
private Entry getEntry(T item){
Entry t = root;
int ret;
//從根節(jié)點(diǎn)開(kāi)始遍歷
for (;t != null;){
ret = item.compareTo(t.item);
if (ret < 0)
t = t.left;
else if (ret > 0)
t = t.right;
else
return t;
}
return null;
}
/**
* 查找后繼節(jié)點(diǎn)
* @param delEntry 刪除節(jié)點(diǎn)
* @return 后繼節(jié)點(diǎn)
*/
private Entry successor(Entry delEntry) {
Entry r = delEntry.right;//r節(jié)點(diǎn)必定不為空
while (r.left != null){
r = r.left;
}
return r;
}
二叉樹(shù)獲取節(jié)點(diǎn)
/**
* 判斷是否存在該元素
* @param item 查找元素
* @return 結(jié)果
*/
public boolean contains(T item){
return getEntry(item) != null;
}
/**
* 獲取節(jié)點(diǎn)節(jié)點(diǎn)
* @param item 獲取節(jié)點(diǎn)
* @return 獲取到的節(jié)點(diǎn),可能為null
*/
private Entry getEntry(T item){
Entry t = root;
int ret;
//從根節(jié)點(diǎn)開(kāi)始遍歷
for (;t != null;){
ret = item.compareTo(t.item);
if (ret < 0)
t = t.left;
else if (ret > 0)
t = t.right;
else
return t;
}
return null;
}
因?yàn)槲疫@個(gè)例子是存儲(chǔ)一個(gè)元素,獲取到的元素和傳進(jìn)去的元素是一致的,所以我用contains方法來(lái)判斷返回true即表示獲取成功了,不返回獲取到的結(jié)果了。當(dāng)然,如果將entry存儲(chǔ)的元素改為kv形式的話,就可以使用get方法了。
二叉樹(shù)的遍歷
二叉樹(shù)的遍歷可以分為三種:前序遍歷、中序遍歷和后續(xù)遍歷,其中中序遍歷是最常用的遍歷方式,因?yàn)樗闅v出來(lái)的結(jié)果的升序的。
前序遍歷:
/**
* 前序遍歷
* @param e 開(kāi)始遍歷元素
*/
public void prevIterator(Entry e){
if (e != null) {
System.out.print(e.item + " ");
prevIterator(e.left);
prevIterator(e.right);
}
}
中序遍歷:
/**
* 中序遍歷
* @param e
*/
public void midIterator(Entry e){
if (e != null){
midIterator(e.left);
System.out.print(e.item + " ");
midIterator(e.right);
}
}
后序遍歷:
/**
* 后續(xù)遍歷
* @param e 開(kāi)始遍歷元素
*/
public void subIterator(Entry e){
if (e != null) {
subIterator(e.left);
subIterator(e.right);
System.out.print(e.item + " ");
}
}
package com.rainple.collections;
/**
* 二叉樹(shù)
* @param
*/
public class BinaryTree> {
//根節(jié)點(diǎn)
private Entry root;
//數(shù)據(jù)量
private int size = 0;
public BinaryTree(){}
/**
* 添加元素
* @param item 待添加元素
* @return 已添加元素
*/
public T put(T item){
//每次添加數(shù)據(jù)的時(shí)候都是從根節(jié)點(diǎn)向下遍歷
Entry t = root;
size++;
if (t == null){
//當(dāng)前的叉樹(shù)樹(shù)的為空,將新節(jié)點(diǎn)設(shè)置為根節(jié)點(diǎn),父節(jié)點(diǎn)為null
root = new Entry<>(item,null);
return root.item;
}
//自然排序結(jié)果,如果傳入的數(shù)據(jù)小于當(dāng)前節(jié)點(diǎn)返回-1,大于當(dāng)前節(jié)點(diǎn)返回1,否則返回0
int ret = 0;
//記錄父節(jié)點(diǎn)
Entry p = t;
while (t != null){
//與當(dāng)前節(jié)點(diǎn)比較
ret = item.compareTo(t.item);
p = t;
//插入節(jié)點(diǎn)比當(dāng)前節(jié)點(diǎn)小,把當(dāng)前節(jié)點(diǎn)設(shè)置為左子節(jié)點(diǎn),然后與左子比較,以此類(lèi)推找到合適的位置
if (ret < 0)
t = t.left;
//大于當(dāng)前節(jié)點(diǎn)
else if (ret > 0)
t = t.right;
else {
//相等就把舊值覆蓋掉
t.item = item;
return t.item;
}
}
//創(chuàng)建新節(jié)點(diǎn)
Entry e = new Entry<>(item,p);
//根據(jù)比較結(jié)果將新節(jié)點(diǎn)放入合適的位置
if (ret < 0)
p.left = e;
else
p.right = e;
return e.item;
}
public void print(){
midIterator(root);
}
/**
* 中序遍歷
* @param e
*/
public void midIterator(Entry e){
if (e != null){
midIterator(e.left);
System.out.print(e.item + " ");
midIterator(e.right);
}
}
/**
* 獲取根節(jié)點(diǎn)
* @return 根節(jié)點(diǎn)
*/
public Entry getRoot(){return root;}
/**
* 前序遍歷
* @param e 開(kāi)始遍歷元素
*/
public void prevIterator(Entry e){
if (e != null) {
System.out.print(e.item + " ");
prevIterator(e.left);
prevIterator(e.right);
}
}
/**
* 后續(xù)遍歷
* @param e 開(kāi)始遍歷元素
*/
public void subIterator(Entry e){
if (e != null) {
subIterator(e.left);
subIterator(e.right);
System.out.print(e.item + " ");
}
}
/**
* 獲取節(jié)點(diǎn)節(jié)點(diǎn)
* @param item 獲取節(jié)點(diǎn)
* @return 獲取到的節(jié)點(diǎn),可能為null
*/
private Entry getEntry(T item){
Entry t = root;
int ret;
//從根節(jié)點(diǎn)開(kāi)始遍歷
for (;t != null;){
ret = item.compareTo(t.item);
if (ret < 0)
t = t.left;
else if (ret > 0)
t = t.right;
else
return t;
}
return null;
}
/**
* 判斷是否存在該元素
* @param item 查找元素
* @return 結(jié)果
*/
public boolean contains(T item){
return getEntry(item) != null;
}
/**
* 刪除元素
* 刪除元素如果細(xì)分的話,可以分為4中:沒(méi)有子節(jié)點(diǎn),只有左節(jié)點(diǎn),只有右節(jié)點(diǎn),有兩個(gè)子節(jié)點(diǎn)
* 1)沒(méi)有子節(jié)點(diǎn)這種情況比較簡(jiǎn)單,直接刪除就可以了
* 2)只有左節(jié)點(diǎn)或右節(jié)點(diǎn),這兩種情況處理方式是一致的,只是方向相反,所以在一起講了,
* 將刪除節(jié)點(diǎn)的父節(jié)點(diǎn)的左節(jié)點(diǎn)(右節(jié)點(diǎn))指向刪除節(jié)點(diǎn)的子節(jié)點(diǎn),將左節(jié)點(diǎn)(右節(jié)點(diǎn))指向刪除節(jié)點(diǎn)的父節(jié)點(diǎn)
* 3)有兩個(gè)子節(jié)點(diǎn),這種情況相對(duì)來(lái)說(shuō)比較復(fù)雜一點(diǎn):
* 找到刪除節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)或后繼節(jié)點(diǎn),然后將前驅(qū)或后繼節(jié)點(diǎn)的值賦給刪除節(jié)點(diǎn),然后將前驅(qū)或后繼節(jié)點(diǎn)刪除。本質(zhì)是刪除前驅(qū)或后繼節(jié)點(diǎn)
* 前驅(qū)節(jié)點(diǎn)的特點(diǎn):
* 1)刪除的左子節(jié)點(diǎn)沒(méi)有右子節(jié)點(diǎn),那么左子節(jié)點(diǎn)即為前驅(qū)節(jié)點(diǎn)
* 2)刪除節(jié)點(diǎn)的左子節(jié)點(diǎn)有右子節(jié)點(diǎn),那么最右邊的最后一個(gè)節(jié)點(diǎn)即為前驅(qū)節(jié)點(diǎn)
* 后繼節(jié)點(diǎn)的特點(diǎn):
* 與前驅(qū)節(jié)點(diǎn)剛好相反,總是右子節(jié)點(diǎn),或則右子節(jié)點(diǎn)的最左子節(jié)點(diǎn);例如:刪除節(jié)點(diǎn)為c ,那么前驅(qū)節(jié)點(diǎn)為 m,后繼節(jié)點(diǎn)為n
* a
* / \
* b c
* / \ / \
* d e f g
* / \ / \ / \ / \
* @param item 刪除元素 h i j k l m n o
* @return 刪除結(jié)果
*/
public boolean remove(T item){
//獲取刪除節(jié)點(diǎn)
Entry delEntry = getEntry(item);
if (delEntry == null) return false;
//刪除節(jié)點(diǎn)的父節(jié)點(diǎn)
Entry p = delEntry.parent;
size--;
//情況1:沒(méi)有子節(jié)點(diǎn)
if (delEntry.left == null && delEntry.right == null){
//刪除節(jié)點(diǎn)為根節(jié)點(diǎn)
if (delEntry == root){
root = null;
}else {//非根節(jié)點(diǎn)
//刪除的是父節(jié)點(diǎn)的左節(jié)點(diǎn)
if (delEntry == p.left){
p.left = null;
}else {//刪除右節(jié)點(diǎn)
p.right = null;
}
}
//情況2:刪除的節(jié)點(diǎn)只有左節(jié)點(diǎn)
}else if (delEntry.right == null){
Entry lc = delEntry.left;
//刪除的節(jié)點(diǎn)為根節(jié)點(diǎn),將刪除節(jié)點(diǎn)的左節(jié)點(diǎn)設(shè)置成根節(jié)點(diǎn)
if (p == null) {
lc.parent = null;
root = lc;
} else {//非根節(jié)點(diǎn)
if (delEntry == p.left){//刪除左節(jié)點(diǎn)
p.left = lc;
}else {//刪除右節(jié)點(diǎn)
p.right = lc;
}
lc.parent = p;
}
//情況3:刪除節(jié)點(diǎn)只有右節(jié)點(diǎn)
}else if (delEntry.left == null){
Entry rc = delEntry.right;
//刪除根節(jié)點(diǎn)
if (p == null) {
rc.parent = null;
root = rc;
}else {//刪除非根節(jié)點(diǎn)
if (delEntry == p.left)
p.left = rc;
else
p.right = rc;
rc.parent = p;
}
//情況4:刪除節(jié)點(diǎn)有兩個(gè)子節(jié)點(diǎn)
}else {//有兩個(gè)節(jié)點(diǎn),找到后繼節(jié)點(diǎn),將值賦給刪除節(jié)點(diǎn),然后將后繼節(jié)點(diǎn)刪除掉即可
Entry successor = successor(delEntry);//獲取到后繼節(jié)點(diǎn)
delEntry.item = successor.item;
//后繼節(jié)點(diǎn)為右子節(jié)點(diǎn)
if (delEntry.right == successor){
//右子節(jié)點(diǎn)有右子節(jié)點(diǎn)
if (successor.right != null) {
delEntry.right = successor.right;
successor.right.parent = delEntry;
}else {//右子節(jié)點(diǎn)沒(méi)有子節(jié)點(diǎn)
delEntry.right = null;
}
}else {//后繼節(jié)點(diǎn)必定是左節(jié)點(diǎn)
successor.parent.left = null;
}
return true;
}
//讓gc回收
delEntry.parent = null;
delEntry.left = null;
delEntry.right = null;
return true;
}
/**
* 查找后繼節(jié)點(diǎn)
* @param delEntry 刪除節(jié)點(diǎn)
* @return 后繼節(jié)點(diǎn)
*/
private Entry successor(Entry delEntry) {
Entry r = delEntry.right;//r節(jié)點(diǎn)必定不為空
while (r.left != null){
r = r.left;
}
return r;
}
public int size(){return size;}
public boolean isEmpty(){return size == 0;}
public void clear(){
clear(getRoot());
root = null;
}
private void clear(Entry e){
if (e != null){
clear(e.left);
e.left = null;
clear(e.right);
e.right = null;
}
}
static final class Entry>{
//保存的數(shù)據(jù)
private T item;
//左子樹(shù)
private Entry left;
//右子樹(shù)
private Entry right;
//父節(jié)點(diǎn)
private Entry parent;
Entry(T item,Entry parent){
this.item = item;
this.parent = parent;
}
}
}
測(cè)試代碼示例:
public static void main(String[] args) {
BinaryTree binaryTree = new BinaryTree<>();
//放數(shù)據(jù)
binaryTree.put(73);
binaryTree.put(22);
binaryTree.put(532);
binaryTree.put(62);
binaryTree.put(72);
binaryTree.put(243);
binaryTree.put(42);
binaryTree.put(3);
binaryTree.put(12);
binaryTree.put(52);
System.out.println("size: " + binaryTree.size());
binaryTree.put(52);
System.out.println("添加相同元素后的size: " + binaryTree.size());
//判斷數(shù)據(jù)是否存在
System.out.println("數(shù)據(jù)是否存在:" + binaryTree.contains(12));
//中序遍歷
System.out.print("中序遍歷結(jié)果: ");
binaryTree.midIterator(binaryTree.getRoot());
System.out.println();
//前序遍歷
System.out.print("前遍歷結(jié)果: ");
binaryTree.prevIterator(binaryTree.getRoot());
System.out.println();
//后序遍歷
System.out.print("后續(xù)遍歷結(jié)果: ");
binaryTree.subIterator(binaryTree.getRoot());
//刪除數(shù)據(jù)
System.out.println();
binaryTree.remove(62);
System.out.println("刪除數(shù)據(jù)后判斷是否存在:" + binaryTree.contains(62));
//清空二叉樹(shù)
binaryTree.clear();
System.out.print("清空數(shù)據(jù)后中序遍歷: ");
binaryTree.midIterator(binaryTree.getRoot());
}
測(cè)試結(jié)果:
size: 10
添加相同元素后的size: 10
數(shù)據(jù)是否存在:true
中序遍歷結(jié)果: 3 12 22 42 52 62 72 73 243 532
前遍歷結(jié)果: 73 22 3 12 62 42 52 72 532 243
后續(xù)遍歷結(jié)果: 12 3 52 42 72 62 22 243 532 73
刪除數(shù)據(jù)后判斷是否存在:false
總結(jié)
以上是生活随笔為你收集整理的java tree类子项的添加和删除_使用Java实现二叉树的添加,删除,获取以及遍历...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 天启3内存选择指南:16GB以上,高速内
- 下一篇: DDR5内存解读:955处理器的性能提升