持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情。
java实现二叉查找树
二叉查找树的特点就是,任意节点大于他的左子节点、小于他的右子节点。最优的情况是根节点的左右子树深度相差一,查找效率直逼二分查找。最差的情况下会退化成单向链表,链表的查找效率是很低下的。
实现二叉查找树的关键就是确认加入左子树还是右子树。
public class BST<T> {
/**
* 二叉查找树,是特殊的二叉树,任意父节点的值大于其左子节点,小于其右子节点
*/
class BSTNode {
//左右子节点
BSTNode lChild;
BSTNode rChild;
//value值
T value;
public BSTNode(T value) {
this.value = value;
}
}
BSTNode root;
public BST() {
this.root = new BSTNode(null);
}
/**
* 插入节点
* @param t
*/
void insert(T t) {
Comparable<? super T> tTemp = (Comparable<? super T>) t;
//可比较的对象
assert t instanceof Comparable;
BSTNode rootTemp = root;
for (; ; ) {
//头节点未初始化
if (rootTemp.value == null) {
rootTemp.value = t;
return;
} else if (tTemp.compareTo(rootTemp.value) > 0) {
if ((rootTemp.rChild) == null) {
rootTemp.rChild = new BSTNode(t);
return;
}
rootTemp = rootTemp.rChild;
} else {
if ((rootTemp.lChild) == null) {
rootTemp.lChild = new BSTNode(t);
return;
}
rootTemp = rootTemp.lChild;
}
}
}
boolean search(T t) {
Comparable<? super T> tTemp = (Comparable<? super T>) t;
//可比较的对象
assert t instanceof Comparable;
BSTNode rootTemp = root;
for (; ; ) {
if (rootTemp == null) {
return false;
} else if (tTemp.compareTo(rootTemp.value) == 0) {
return true;
} else if (tTemp.compareTo(rootTemp.value) > 0) {
rootTemp = rootTemp.rChild;
} else if (tTemp.compareTo(rootTemp.value) < 0) {
rootTemp = rootTemp.lChild;
}
}
}
@Test
public void test() {
BST<Integer> integerBST = new BST<>();
integerBST.insert(6);
integerBST.insert(2);
integerBST.insert(3);
integerBST.insert(1);
integerBST.insert(5);
integerBST.insert(9);
integerBST.insert(10);
integerBST.insert(120);
System.out.println(integerBST.search(2));
System.out.println(integerBST.search(10000));
System.out.println(integerBST.search(10));
System.out.println(integerBST.search(10));
System.out.printlnt(integerBST.search(120));
System.out.println(integerBST.search(5));
}
}
复制代码
java实现平衡二叉树
平衡二叉树是特殊的二叉查找树,为了防止二叉查找树退化成链表,在插入和删除节点的时候会检测左右子树的深度差小于1,如果深度差大于1就会进行旋转,旋转理论和图示在上一篇说过了,这里就实现。重要的就是旋转的逻辑。
public class AVLTree<T> {
@Data
@AllArgsConstructor
@NoArgsConstructor
class AVLNode {
//左右子节点
AVLNode lChild;
AVLNode rChild;
//value值
T value;
//该节点节对应子树高度
int height;
public AVLNode(T value) {
this.value = value;
}
}
private AVLNode root;
public AVLTree() {
}
/**
* 插入节点
* <p>
* 节点的高度如何确定
* <p>
* -左边插入一个
*
* @param t
*/
void insert(T t) {
root = insert(root, t);
}
private AVLNode insert(AVLNode root, T t) {
//可比较的对象
assert t instanceof Comparable;
Comparable<? super T> tTemp = (Comparable<? super T>) t;
//节点未初始化,递归出口
if (ObjectUtils.isEmpty(root)) {
root = new AVLNode(t);
return root;
}
//插入右子树
else if (tTemp.compareTo(root.value) > 0) {
root.rChild = insert(root.rChild, t);
//右右情况
if (bf(root.rChild) < -1) {
root = rrRotate(root);
}
//右左情况
else if (bf(root.rChild) > 1) {
root = rlRotate(root);
}
}
//插入左子树
else {
root.lChild = insert(root.lChild, t);
//左左情况
if (bf(root.lChild) > 1) {
root = llRotate(root);
}
//左右情况
else if (bf(root.lChild) < -1) {
root = lrRotate(root);
}
}
//插入新节点跟新子树高度
root.height = height(root);
return root;
}
private AVLNode element(AVLNode node, T t) {
assert t instanceof Comparable;
Comparable tTemp = (Comparable) t;
if (tTemp.compareTo(node.value) == 0)
return node;
else if (tTemp.compareTo(node.value) > 0)
return element(node.rChild, t);
else
return element(node.lChild, t);
}
public AVLNode element(T t) {
return element(root, t);
}
//递归计算节点高度
private int height(AVLNode node) {
//当前节点为空,直接返回-1
if (node == null) return -1;
//当前节点左右节点为空,返回0
if (node.lChild == null && node.rChild == null)
return 0;
else {
return Math.max(height(node.lChild), height(node.rChild)) + 1;
}
}
//判断树是否不平衡
private Boolean isBalance(AVLNode root) {
return Math.abs(height(root.lChild) - height(root.rChild)) <= 1;
}
//小于0,右子树高 大于0 左子树高
private int bf(AVLNode root) {
return height(root.lChild) - height(root.rChild);
}
//左左情况
private AVLNode llRotate(AVLNode root) {
AVLNode lChild = root.lChild;
//左子树的右节点为,根节点的左节点
root.lChild = lChild.rChild;
root.height = height(root);
//左子树的右节点,为根节点
lChild.rChild = root;
//左左情况,只需要跟新 k1 和 k2高度,其他节点的子树叶子节点没有变化
lChild.height = height(lChild);
//新的根节点
return lChild;
}
//右右情况
private AVLNode rrRotate(AVLNode root) {
AVLNode rChild = root.rChild;
//左子树的右节点为,根节点的左节点
root.rChild = rChild.lChild;
root.height = height(root);
//左子树的右节点,为根节点
rChild.lChild = root;
rChild.height = height(rChild);
//新的根节点
return rChild;
}
//左右情况
private AVLNode lrRotate(AVLNode root) {
//先将左子树进行右旋,并跟新
root.lChild = rrRotate(root.lChild);
//再将原树进行左旋
return llRotate(root);
}
//右左情况
private AVLNode rlRotate(AVLNode root) {
//先将右子树进行左旋,并跟新
root.rChild = llRotate(root.rChild);
//再将原树进行右旋
return rrRotate(root);
}
public static void main(String[] args) {
AVLTree<Integer> integerAVLTree = new AVLTree<Integer>();
integerAVLTree.insert(8);
integerAVLTree.insert(9);
integerAVLTree.insert(10);
integerAVLTree.insert(1);
integerAVLTree.insert(2);
integerAVLTree.insert(3);
integerAVLTree.insert(4);
integerAVLTree.insert(6);
integerAVLTree.insert(5);
//验证高度
System.out.println(integerAVLTree.height(integerAVLTree.root));
System.out.println(integerAVLTree.root.height);
//查询节点
System.out.println(integerAVLTree.element(8));
}
}
复制代码
java实现字典树
多叉树除了红黑树外,还有一种·trie·树,又叫字典树,专门用于匹配字符串用的。除了根节点,每一个节点都代表一个字符,每一条路径都代表一个字符串,每一个节点都存储着多个子节点引用。
public class TrieTest {
/**
* 字典树节点
* <p>
* 每个节点有多个子节点,且子节点互不重复
*/
static class TrieNode {
//子节点
HashMap<Character, TrieNode> children = new HashMap<>();
//字符串结束标志
Boolean isEnd;
public TrieNode() {
this.children = new HashMap<Character, TrieNode>();
this.isEnd = false;
}
}
//字典树根节点
private TrieNode root;
public TrieTest() {
this.root = new TrieNode();
}
//插入字典树
void insert(String value) {
TrieNode nodeTemp = root;
for (int i = 0; i < value.length(); i++) {
//获取字符
Character c = value.charAt(i);
//是否包含此节点
if (!nodeTemp.children.containsKey(c)) {
nodeTemp.children.put(c, new TrieNode());
}
nodeTemp = nodeTemp.children.get(c);
}
//最后一个插入的字符为叶子节点
nodeTemp.isEnd = true;
}
//查找 也是从根节点开始搜索
boolean search(String value) {
TrieNode nodeTemp = root;
for (int i = 0; i < value.length(); i++) {
//获取字符
Character c = value.charAt(i);
//是否包含此节点
if (!nodeTemp.children.containsKey(c)) {
return false;
}
nodeTemp = nodeTemp.children.get(c);
}
return nodeTemp.isEnd;
}
@Test
public void test() {
TrieTest trieTest = new TrieTest();
String[] values = new String[]{"a", "to", "tea", "ted", "ten", "i", "in", "ind", "ifd"};
for (int i = 0; i < values.length; i++) {
trieTest.insert(values[i]);
}
System.out.println("==是否包含ten==>" + trieTest.search("ten"));
System.out.println("==是否包含xxxx==>" + trieTest.search("xxxx"));
}
}
复制代码