当前位置: 首页 > news >正文

【188】Java8利用AVL树实现Map

AVL树又被叫做平衡二叉搜索树、平衡二叉树。AVL是其发明者的首字母缩写。

这篇文章中,AVLTreeMap 类集成了 java.util.Map 接口,并利用 AVL 树结构实现了 Map 接口的所有方法。本文还给出了测试代码。

为什么要发明AVL树?

当我按照从小到大或者从大到小的顺序向二叉查找树插入节点,二叉查找树就会退化成一个链表。这是二叉查找树的最差情况。搜索、插入、删除的最差效率都是 O(N)。这样就失去了用二叉查找树优化查找方法的意义。

就算不是最坏情况,也会出现非常不平衡的树,造成查找效率大于 O(logN) 小于 O(N) 。注意这里 logN 是以2为底N的对数。

AVL树的时间复杂度

因为含有数学公式,就使用图片了。
在这里插入图片描述

在这里插入图片描述

代码实现

AVLTreeMap.java


package zhangchao.avl;import java.util.*;/*** 利用AVL树,也就是平衡二叉树来实现map* @author zhangchao* @param <K> 键* @param <V> 值*/
public class AVLTreeMap<K,V> implements Map<K, V>{// 根节点private Node<K, V> root = null;private Comparator<K> comparator;public AVLTreeMap(Comparator<K> comparator) {this.comparator = comparator;}@Overridepublic int size() {if (null == root) {return 0;}int size = 0;// 当前层的节点列表List<Node<K, V>> currentLevel = new ArrayList<>();currentLevel.add(root);while (!currentLevel.isEmpty()) {size += currentLevel.size();// 下一层的节点列表List<Node<K, V>> nextLevel = new ArrayList<>();for (Node<K, V> tmpNode : currentLevel) {if (null != tmpNode.leftChild) {nextLevel.add(tmpNode.leftChild);}if (null != tmpNode.rightChild) {nextLevel.add(tmpNode.rightChild);}}currentLevel.clear();currentLevel.addAll(nextLevel);}return size;}@Overridepublic boolean isEmpty() {return (null == root);}@Overridepublic boolean containsKey(Object keyObj) {if (null == root) {return false;}K key = (K)keyObj;Node<K, V> current = this.root;while(null != current) {int compareResult = this.comparator.compare(key, current.key);if (compareResult < 0) {current = current.leftChild;} else if (compareResult > 0) {current = current.rightChild;} else {return true;}}return false;}@Overridepublic boolean containsValue(Object value) {if (null == this.root) {return false;}List<Node<K, V>> nodeList = this.nodeList();for (Node<K, V> node : nodeList) {if (null == value && null == node.value) {return true;}if (null != value && value.equals(node.value)) {return true;}}return false;}@Overridepublic V get(Object keyObj) {if (null == this.root) {return null;}K key = (K)keyObj;Node<K, V> current = this.root;while(null != current) {int compareResult = this.comparator.compare(key, current.key);if (compareResult < 0) {current = current.leftChild;} else if (compareResult > 0) {current = current.rightChild;} else {return current.value;}}return null;}/*** 右旋操作* @param parent 爷爷节点* @param y 父级节点* @param x 子级节点*/private void rotateRight(Node<K, V> parent, Node<K, V> y, Node<K, V> x) {y.leftChild = x.rightChild;x.rightChild = y;if (null == parent) {this.root = x;} else {// 判断原来的y是parent的左子节点还是右子节点。if (null != parent.leftChild && 0 == this.comparator.compare(parent.leftChild.key, y.key)) {parent.leftChild = x;} else if (null != parent.rightChild && 0 == this.comparator.compare(parent.rightChild.key, y.key)) {parent.rightChild = x;}}y.height = this.calHeight(y);x.height = this.calHeight(x);if (null != parent) {parent.height = this.calHeight(parent);}}/*** 左旋操作* @param parent 爷爷节点* @param y 父级节点* @param x 子级节点*/private void rotateLeft(Node<K, V> parent, Node<K, V> y, Node<K, V> x) {y.rightChild = x.leftChild;x.leftChild = y;if (null == parent) {this.root = x;} else {// 判断原来的y是parent的左子节点还是右子节点。if (null != parent.leftChild && 0 == this.comparator.compare(parent.leftChild.key, y.key)) {parent.leftChild = x;} else if (null != parent.rightChild && 0 == this.comparator.compare(parent.rightChild.key, y.key)) {parent.rightChild = x;}}y.height = this.calHeight(y);x.height = this.calHeight(x);if (null != parent) {parent.height = this.calHeight(parent);}}@Overridepublic V put(K key, V value) {if (null == this.root) {this.root = new Node<>();this.root.key = key;this.root.value = value;this.root.height = 1;return null;}// 如果key是全新的,保存所有的父亲节点。List<Node<K, V>> linkList = new ArrayList<>();// 如果key是全新的,这个变量是新节点的父亲节点。Node<K, V> parent = null;Node<K, V> current = root;int compareResult = 0;while (null != current) {compareResult = this.comparator.compare(key, current.key);if (compareResult < 0) {parent = current;linkList.add(parent);current = current.leftChild;} else if (compareResult > 0) {parent = current;linkList.add(parent);current = current.rightChild;} else {// 有相等的key,直接设置值就可以了。V oldValue = current.value;current.value = value;return oldValue;}}Node<K, V> newItem = new Node<K, V>();newItem.key = key;newItem.value = value;newItem.height = 1;if (compareResult < 0) {parent.leftChild = newItem;} else if (compareResult > 0) {parent.rightChild = newItem;}// 更新祖先节点的高度final int size = linkList.size();for (int i = size - 1; i >= 0; i--) {Node<K, V> item = linkList.get(i);item.height = calHeight(item);}linkList.add(newItem);int parentSize = linkList.size();for (int i = parentSize - 1; i >= 0; i--) {// 当前节点Node<K, V> z = linkList.get(i);// z的父节点,如果z是根节点,那么就是null。Node<K, V> z_parent = null;if (i > 0) {z_parent = linkList.get(i - 1);}int leftHeight = this.calHeight(z.leftChild);int rightHeight = this.calHeight(z.rightChild);int balance = leftHeight - rightHeight;if (balance > 1) { // LL 或 LRNode<K, V> y = z.leftChild;Node<K, V> x = linkList.get(i + 2);boolean isLL = (null != y.leftChild  && this.comparator.compare(y.leftChild.key, x.key) == 0);boolean isLR = (null != y.rightChild && this.comparator.compare(y.rightChild.key, x.key) == 0);if (isLL) { // LL 右旋this.rotateRight(z_parent, z, y);}else if (isLR) {    // LR// y和x之间左旋this.rotateLeft(z, y, x);// z和x之间右旋this.rotateRight(z_parent, z, x);}break; // 停止for循环} else if (balance < -1) { // RR 或 RLNode<K, V> y = z.rightChild;Node<K, V> x = linkList.get(i + 2);boolean isRR = (null != y.rightChild && this.comparator.compare(y.rightChild.key, x.key) == 0);boolean isRL = (null != y.leftChild && this.comparator.compare(y.leftChild.key, x.key) == 0);if (isRR) {this.rotateLeft(z_parent, z, y);} else if (isRL) {// y和x之间右旋this.rotateRight(z, y, x);// z和x之间左旋this.rotateLeft(z_parent, z, x);}break; // 停止for循环}}// 更新祖先节点高度for (int i = parentSize - 1; i >= 0; i--) {Node<K, V> item = linkList.get(i);item.height = calHeight(item);}return null;}private List<Node<K,V>> getNodeAndParent(K key, List<Node<K, V>> parents) {if (null == this.root) {return null;}Node<K, V> parent = null;Node<K, V> current = this.root;while(null != current) {int compareResult = this.comparator.compare(key, current.key);if (compareResult < 0) {parent = current;if (null != parents) {parents.add(parent);}current = current.leftChild;} else if (compareResult > 0) {parent = current;if (null != parents) {parents.add(parent);}current = current.rightChild;} else {List<Node<K, V>> result = new ArrayList<>();result.add(current);result.add(parent);return result;}}return null;}private K deleteAsBST(Node<K, V> node, Node<K, V> parent) {K endKey = null;// 叶子节点if (null == node.leftChild && null == node.rightChild) {if (node == parent.leftChild) {parent.leftChild = null;} else {parent.rightChild = null;}return parent.key;}// 左子节点为空,只有右子节点else if (null == node.leftChild && null != node.rightChild) {if (node == this.root) {this.root = node.rightChild;} else if (node == parent.leftChild) {parent.leftChild = node.rightChild;} else if (node == parent.rightChild) {parent.rightChild = node.rightChild;}endKey = node.rightChild.key;node.rightChild = null;return endKey;}// else 包含两种情况:// 1.左子节点不为空,右子为空// 2.左子节点不为空,右子不为空// 要删除的节点的左子树中,找出最大节点。Node<K, V> current = node.leftChild;Node<K, V> currentParent = node;while (null != current.rightChild) {currentParent = current;current = current.rightChild;}// 把current从原位置删除if (current == currentParent.leftChild) {currentParent.leftChild = current.leftChild;} else if (current == currentParent.rightChild) {currentParent.rightChild = current.leftChild;}// 让current取代node的位置if (node == this.root) {this.root = current;} else if (node == parent.leftChild) {parent.leftChild = current;} else {parent.rightChild = current;}current.leftChild = node.leftChild;current.rightChild = node.rightChild;node.leftChild = null;node.rightChild = null;if (null == current.leftChild) {return current.key;} else {Node<K, V> p1 = current.leftChild;while (null != p1.rightChild) {p1 = p1.rightChild;}return p1.key;}}@Overridepublic V remove(Object keyObj) {// 空map,不执行删除操作。if (null == this.root) {return null;}K key = (K)keyObj;// 只有根节点的情况if (null == this.root.leftChild && null == this.root.rightChild) {if (this.comparator.compare(key ,this.root.key) == 0) {V v = this.root.value;this.root = null;return v;} else {return null;}}// 不包含key就返回nullList<Node<K, V>> nodeAndParent = this.getNodeAndParent(key, new ArrayList<>());// map中没有对应的key,不执行删除操作。if (null == nodeAndParent || nodeAndParent.isEmpty()) {return null;}Node<K, V> node = nodeAndParent.get(0); // 要删除的节点V result = node.value;Node<K, V> parent = nodeAndParent.get(1); // 要删除的节点的父亲节点// 按照二叉搜索树(BST)的方式删除节点。返回结束节点的键。K endKey = this.deleteAsBST(node, parent);// 包含所有可能改动过高度的节点的列表。// 顺序是从根节点向下。// 替换了已删除节点位置的节点称为替换节点。// pathList的内容有以下三种情况:// 1. 叶子节点,pathList包含根节点到父节点。// 2. 没有左子节点,只有右子节点,pathList包含根节点到替换节点。// 3. 有左子节点,pathList包含根节点到替换节点,再加上替换节点到替换节点左子树最大节点。List<Node<K, V>> pathList = new ArrayList<>();List<Node<K,V>> endKeyResult = this.getNodeAndParent(endKey, pathList);pathList.add(endKeyResult.get(0));// 因为可能加入了节点,所以要重新计算 parents 的长度int size = pathList.size();for (int i = size - 1; i >= 0; i--) {Node<K, V> z_parent = i > 0 ? pathList.get(i - 1) : null;Node<K, V> z = pathList.get(i);// 更新高度z.height = this.calHeight(z);if (null != z_parent) {z_parent.height = this.calHeight(z_parent);}int leftHeight = calHeight(z.leftChild);int rightHeight = calHeight(z.rightChild);int balance = leftHeight - rightHeight;if (balance > 1) {Node<K, V> y = z.leftChild;Node<K, V> x = null;int y_leftHeight = calHeight(y.leftChild);int y_rightHeight = calHeight(y.rightChild);if (y_leftHeight >= y_rightHeight) {// LLx = y.leftChild;// z和y之间右旋this.rotateRight(z_parent, z, y);} else {// LRx = y.rightChild;// y和x之间左旋this.rotateLeft(z, y, x);// z和x之间右旋this.rotateRight(z_parent, z, x);}} else if (balance < -1) {Node<K, V> y = z.rightChild;Node<K, V> x = null;int y_leftHeight = calHeight(y.leftChild);int y_rightHeight = calHeight(y.rightChild);if (y_leftHeight >= y_rightHeight) {// RLx = y.leftChild;// y和x之间右旋this.rotateRight(z, y, x);// z和x之间左旋this.rotateLeft(z_parent, z, x);} else {// RRx = y.rightChild;// z和y之间左旋this.rotateLeft(z_parent, z, y);}}}return result;}// end public V remove(Object keyObj)@Overridepublic void putAll(Map<? extends K, ? extends V> m) {if (null == m) {return;}Set<? extends K> keySet = m.keySet();for (K key : keySet) {this.put(key, m.get(key));}}@Overridepublic void clear() {this.root = null;}private List<Node<K, V>> nodeList() {if (null == this.root) {return new ArrayList<Node<K, V>>();}List<Node<K, V>> result = new ArrayList<>();Stack<Node<K, V>> stack = new Stack<>();Node<K, V> current = this.root;while(null != current || !stack.isEmpty()) {while (null != current) {stack.push(current);current = current.leftChild;}current = stack.pop();// 放入结果列表中result.add(current);current = current.rightChild;}return result;}@Overridepublic Set<K> keySet() {List<Node<K, V>> nodeList = nodeList();Set<K> set = new TreeSet<>(this.comparator);for (Node<K, V> node : nodeList) {set.add(node.key);}return set;}@Overridepublic Collection<V> values() {List<Node<K, V>> nodeList = nodeList();List<V> result = new ArrayList<>();for (Node<K,V> node : nodeList) {result.add(node.value);}return result;}@Overridepublic Set<Entry<K, V>> entrySet() {List<Node<K, V>> nodeList = this.nodeList();Set<Entry<K, V>> set = new TreeSet<Entry<K, V>>((o1, o2) -> {Node<K, V> n1 = (Node<K, V>) o1;Node<K, V> n2 = (Node<K, V>) o2;return comparator.compare(n1.key, n2.key);});for (Node<K,V> node : nodeList) {set.add(node);}return set;}private int calHeightForCheck(Node<K,V> node) {if (null == node) {return 0;}int height = 0;List<Node<K,V>> currentLevel = new ArrayList<>();currentLevel.add(node);while (!currentLevel.isEmpty()) {height ++;List<Node<K,V>> nextLevel = new ArrayList<>();for (Node<K,V> tmpNode : currentLevel) {if (null != tmpNode.leftChild) {nextLevel.add(tmpNode.leftChild);}if (null != tmpNode.rightChild) {nextLevel.add(tmpNode.rightChild);}}currentLevel = nextLevel;}return height;}private void showTree(Node node, Node parent, int level, String prefix) {if (null == node) {return;}StringBuilder sb = new StringBuilder();for (int i = 0; i < level; i++) {sb.append("  ");}sb.append(prefix);sb.append(node.key).append("         ");if (parent != null) {sb.append(parent.key);}int balance = calHeightForCheck(node.leftChild) - calHeightForCheck(node.rightChild);sb.append("    ").append(balance);System.out.println(sb);level++;showTree(node.leftChild, node, level, "left : ");showTree(node.rightChild, node, level, "right: ");}/*** 打印树形结构。*/public void showTree() {if (null == root) {System.out.println("null");}showTree(root, null, 0, "root: ");}private void checkTree(Node node, Node parent, int level) {if (null == node) {return;}int balance = calHeightForCheck(node.leftChild) - calHeightForCheck(node.rightChild);if (balance < -1 || balance > 1) {throw new RuntimeException("balance < -1 || balance > 1");}level++;checkTree(node.leftChild, node, level);checkTree(node.rightChild, node, level);}/*** 检查树是不是符合AVL树的要求*/public void checkTree() {if (null == root) {return;}checkTree(root, null, 0);}/*** 以node为根节点,计算树的高度* @param node 根节点* @return 树的高度*/private int calHeight(Node<K,V> node) {if (null == node) {return 0;}int leftHeight = (null == node.leftChild) ? 0 : node.leftChild.height;int rightHeight = (null == node.rightChild) ? 0 : node.rightChild.height;return Math.max(leftHeight, rightHeight) + 1;}class Node<K,V> implements Entry<K,V> {K key = null;V value = null;int height;Node<K, V> leftChild;Node<K, V> rightChild;@Overridepublic K getKey() {return key;}@Overridepublic V getValue() {return value;}@Overridepublic V setValue(V tmpValue) {V oldValue = value;value = tmpValue;return oldValue;}public int getHeight() {return height;}}
}

测试代码 TestAVLTreeMap.java
这里面有和二叉查找树Map的对比。
二叉查找树Map的实现文章:https://blog.csdn.net/zhangchao19890805/article/details/128609922?spm=1001.2014.3001.5502


package zhangchao.avl.test;import zhangchao.avl.AVLTreeMap;import zhangchao.bst.BstTreeMap;import java.util.*;public class TestAVLTreeMap {public static void main(String[] args) {t7();}public static void t7() {int a[] = {20, 10, 21, 22, 5, 15, 1};Comparator<Integer> comparator = (o1, o2) ->{if (null == o1 && null == o2) {return 0;}if (null == o1 && null != o2) {return -1;}if (null != o1 && null == o2) {return 1;}return o1 - o2;};AVLTreeMap<Integer, String> avlTreeMap = new AVLTreeMap<>(comparator );for (int key : a) {avlTreeMap.put(key, "__" + key);}avlTreeMap.showTree();avlTreeMap.remove(20);System.out.println("\n");avlTreeMap.showTree();avlTreeMap.checkTree();}public static void t6() {Comparator<Integer> comparator = (o1, o2) ->{if (null == o1 && null == o2) {return 0;}if (null == o1 && null != o2) {return -1;}if (null != o1 && null == o2) {return 1;}return o1 - o2;};AVLTreeMap<Integer, String> avlTreeMap = new AVLTreeMap<>(comparator );BstTreeMap<Integer, String> bstTreeMap = new BstTreeMap<>(comparator);long t1;long t2;// 比对插入System.out.println("insert");Random r = new Random();final int MAX = 100000;List<Integer> list = new ArrayList<>();for (int i = 0; i < MAX; i++) {int key = r.nextInt(MAX);list.add(i);}t1 = System.currentTimeMillis();for (int key : list) {avlTreeMap.put(key, "__" + key);}t2 = System.currentTimeMillis();System.out.println("AVL:" + (t2 - t1));t1 = System.currentTimeMillis();for (int key : list) {bstTreeMap.put(key, "__" + key);}t2 = System.currentTimeMillis();System.out.println("BST:" + (t2 - t1));// 比对查询System.out.println("\nsearch");t1 = System.currentTimeMillis();for (int i = 0; i < MAX; i++) {avlTreeMap.get(i);}t2 = System.currentTimeMillis();System.out.println("AVL:" + (t2 - t1));t1 = System.currentTimeMillis();for (int i = 0; i < MAX; i++) {bstTreeMap.get(i);}t2 = System.currentTimeMillis();System.out.println("BST:" + (t2 - t1));
//        avlTreeMap.showTree();//      比对删除System.out.println("\nremove");t1 = System.currentTimeMillis();Collections.shuffle(list);for (int key : list) {avlTreeMap.remove(key);}t2 = System.currentTimeMillis();System.out.println("AVL:" + (t2 - t1));t1 = System.currentTimeMillis();for (int key : list) {bstTreeMap.remove(key);}t2 = System.currentTimeMillis();System.out.println("BST:" + (t2 - t1));avlTreeMap.checkTree();}public static void t3() {Map<Integer, String> map = new AVLTreeMap<>( (o1, o2) ->{if (null == o1 && null == o2) {return 0;}if (null == o1 && null != o2) {return -1;}if (null != o1 && null == o2) {return 1;}return o1 - o2;});int[] arr = new int[]{20,10,21,5,15,22,13,16};for (int i : arr) {map.put(i, "__" + String.valueOf(i));}AVLTreeMap avlTreeMap = (AVLTreeMap) map;avlTreeMap.showTree();avlTreeMap.remove(10);System.out.println("\n");avlTreeMap.showTree();avlTreeMap.checkTree();}public static void t2() {Map<Integer, String> map = new AVLTreeMap<>( (o1, o2) ->{if (null == o1 && null == o2) {return 0;}if (null == o1 && null != o2) {return -1;}if (null != o1 && null == o2) {return 1;}return o1 - o2;});int[] arr = new int[]{8,3,6,1,2,98,2,6,150,170,160,7,52,28,75,14,40,86,10,21,46,25};for (int i : arr) {map.put(i, "__" + String.valueOf(i));}AVLTreeMap avlTreeMap = (AVLTreeMap) map;avlTreeMap.showTree();avlTreeMap.remove(7);System.out.println("\n\n\n");avlTreeMap.showTree();avlTreeMap.checkTree();}public static void t1() {Map<Integer, String> map = new AVLTreeMap<>( (o1, o2) ->{if (null == o1 && null == o2) {return 0;}if (null == o1 && null != o2) {return -1;}if (null != o1 && null == o2) {return 1;}return o1 - o2;});int[] arr = new int[]{8,3,6,1,2,98,2,6,150,170,160,7,52,28,75,14,40,86,10,21,46,25};for (int i : arr) {map.put(i, "__" + String.valueOf(i));}AVLTreeMap avlTreeMap = (AVLTreeMap) map;avlTreeMap.showTree();System.out.println(map.get(3));System.out.println(map.get(6));System.out.println(map.get(98));System.out.println(map.get(null));Set<Integer> set = avlTreeMap.keySet();for (Integer i : set) {System.out.println(i);}System.out.println();HashSet<Integer> hashSet = new HashSet<>();for (int i : arr) {hashSet.add(i);}for (int i : hashSet) {if (!set.contains(i)) {System.out.println(false);}}System.out.println(set.size() + "   " + hashSet.size());System.out.println("containsKey 3: " + avlTreeMap.containsKey(3));System.out.println("containsKey 4: " + avlTreeMap.containsKey(4));System.out.println("containsValue __3: " + avlTreeMap.containsValue("__3"));System.out.println("containsValue __4: " + avlTreeMap.containsValue("__4"));System.out.println();Set<Map.Entry<Integer, String>> entrySet = avlTreeMap.entrySet();for (Map.Entry<Integer, String> item : entrySet) {System.out.println(item.getKey() + ": " + item.getValue());}avlTreeMap.checkTree();}
}

相关文章:

【188】Java8利用AVL树实现Map

AVL树又被叫做平衡二叉搜索树、平衡二叉树。AVL是其发明者的首字母缩写。 这篇文章中&#xff0c;AVLTreeMap 类集成了 java.util.Map 接口&#xff0c;并利用 AVL 树结构实现了 Map 接口的所有方法。本文还给出了测试代码。 为什么要发明AVL树&#xff1f; 当我按照从小到大…...

[SQL挖掘机] - 右连接: right join

介绍: 右连接是一种多表连接方式&#xff0c;它以右侧的表为基础&#xff0c;并返回满足连接条件的匹配行以及右侧表中的所有行&#xff0c;即使左侧的表中没有匹配的行。右连接将右表的每一行与左表进行比较&#xff0c;并根据连接条件返回结果集。其实, 左连接和右连接原理一…...

bug篇之基于docker安装nacos(2.1.1)使用dubbo连接不上的问题

说明&#xff1a;首先我的nacos安装是2.1.1版本&#xff0c;请注意版本问题。另外启动时用dubbo的话必须先启动服务提供者再启动服务使用者&#xff0c;否则会报错&#xff0c;同时也必须开放三个端口&#xff1a;8848&#xff0c;9848&#xff0c;9849 java.lang.IllegalStat…...

【Python入门系列】第二十一篇:Python物联网和传感器应用

文章目录 前言一、Python在物联网和传感器应用中的优势二、连接传感器和设备三、读取传感器数据四、示例代码和讲解五、进一步处理和分析传感器数据六、更多应用示例1、温湿度监测系统2、智能家居系统 - 灯光控制 总结 前言 物联网和传感器在现代科技中扮演着重要的角色。物联…...

Python爬虫的urlib的学习(学习于b站尚硅谷)

目录 一、页面结构的介绍  1.学习目标  2.为什么要了解页面&#xff08;html&#xff09;  3. html中的标签&#xff08;仅介绍了含表格、无序列表、有序列表、超链接&#xff09;  4.本节的演示 二、Urllib  1.什么是互联网爬虫&#xff1f;  2.爬虫核心  3.爬虫…...

【MongoDB】--MongoDB聚合Aggregation

目录 一、前言二、聚合管道操作2.1、实际案例1(1)、案例--根据学生no&#xff0c;找到对应班级名称(2)、案例--这个班级有哪些学生和哪些老师在任课 2.2、实际案例2(1)、案例--主表和关联表都有条件限制&#xff0c;且分页返回 一、前言 聚合操作组值来自多个文档&#xff0c;…...

Hadoop学习指南:探索大数据时代的重要组成——Hadoop概述

前言 在当今大数据时代&#xff0c;处理海量数据成为了一项关键任务。Hadoop作为一种开源的分布式计算框架&#xff0c;为大规模数据处理和存储提供了强大的解决方案。本文将介绍Hadoop的组成和其在大数据处理中的重要作用&#xff0c;让我们一同踏上学习Hadoop的旅程。 Hado…...

Java实现简单小画板

Java制作简单画板&#xff0c;包括两个类&#xff0c;一个主要画板类Drawpad&#xff0c;一个画板监听器DrawListener类。 1、Drawpad类&#xff0c;包括画板&#xff0c;画板功能设计&#xff0c;保存图片等 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 2…...

B078-项目实战--支付模块 领养订单支付流程

目录 支付模块需求分析表设计支付单表支付宝账号信息表-商家账号微信支付账号信息表-商家账号银行账号表-商家资金账号表支付流水表 流程分析支付基础模块继承加密算法沙箱环境准备支付宝支付-流程分析根据demo封装工具类导入依赖AlipayConfigAlipayInfoAlipayUtil 内网穿透 领…...

[css]margin-top不起作用问题(外边距合并)

在初学css时&#xff0c;会遇到突然间margin-top不起作用的情况。如下面&#xff1a; 情况一&#xff1a; 代码&#xff1a; <html> <head><style type"text/css"> * {margin:0;padding:0;border:0; }#outer {width:300px;height:300px;backgroun…...

Vue2基础八、插槽

零、文章目录 Vue2基础八、插槽 1、插槽 &#xff08;1&#xff09;默认插槽 作用&#xff1a;让组件内部的一些 结构 支持 自定义需求: 将需要多次显示的对话框, 封装成一个组件问题&#xff1a;组件的内容部分&#xff0c;不希望写死&#xff0c;希望能使用的时候自定义。…...

自然语言处理从入门到应用——LangChain:提示(Prompts)-[提示模板:连接到特征存储]

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 特征存储是传统机器学习中的一个概念&#xff0c;它确保输入模型的数据是最新和相关的。在考虑将LLM应用程序投入生产时&#xff0c;这个概念非常重要。为了个性化LLM应用程序&#xff0c;我们可能希望将LLM与特定用户…...

jenkins自定义邮件发送人姓名

jenkins发送邮件的时候发送人姓名默认的&#xff0c;如果要自定义发件人姓名&#xff0c;只需要修改如下信息即可&#xff1a; 系统管理-system-Jenkins Location下的系统管理员邮件地址 格式为&#xff1a;自定义姓名<邮件地址>...

SolidWorks二次开发---简单的连接solidworks

创建一个.net Framework的应用&#xff0c;正常4.0以上就可以了。 打开nuget包管理 在里面搜索paine 在版中选择对应的solidworks年份开头的&#xff0c;进行安装。 安装完之后 : 同时选中下面两个dll,把嵌入操作类型改为false 然后在按钮的单击事件中输入: Connect.Crea…...

docker 安装 active Mq

在安装完Docker的机器上&#xff0c;安装activeMQ。 拉取镜像&#xff1a; docker pull webcenter/activemq 查看镜像&#xff1a; docker images Docker运行ActiveMQ镜像 docker run --name activemq -d -p 8161:8161 -p 61616:61616 --privilegedtrue --restartalways …...

【Linux】TCP协议

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;TCP协议&…...

DevOps系列文章之 自动化测试大全(单测和集成测试)

自动化测试业界主流工具 核心目标&#xff1a; 主要是功能测试和覆盖率测试 业界常用主流工具 GoogleTest GoogleTest是一个跨平台的(Liunx、Mac OS X、Windows 、Cygwin 、Windows CE and Symbian ) C单元测试框架&#xff0c;由google公司发布&#xff0c;为在不同平台上为编…...

Android启动速度优化

本节主要内容&#xff1a;了解APP启动流程、启动状态、查看启动时间、CPU Profile定位启动耗时代码、StrictMode严苛模式检测不合理写法、解决启动黑白屏问题。 一、APP启动流程 ①用户点击桌面App图标&#xff0c;Launcher进程采用Binder IPC向system_server进程发起startAc…...

linux 日志 系统安全日志 web日志

web日志 LINUX日志系统之WEB日志&#xff08;一&#xff09;_dracut.log_麻子来了的博客-CSDN博客 系统安全日志 Linux系统安全日志详解_sinolover的博客-CSDN博客 wtmp和utmp文件都是二进制文件&#xff0c;需使用who、w、users、last和ac来操作这两个文件。 who /var/lo…...

SpringBoot 整合 MongoDB 连接 阿里云MongoDB

注&#xff1a;spring-boot-starter-data-mongodb 2.7.5&#xff1b;jdk 1.8 阿里云MongoDB是副本集实例的 在网上查找了一番&#xff0c;大多数都是教连接本地mongodb或者linux上的mongodb 阿里云上有java版连接教程&#xff0c;但它不是SpringBoot方法配置的&#xff0c;是手…...

Debeizum 增量快照

在Debeizum1.6版本发布之后&#xff0c;成功推出了Incremental Snapshot&#xff08;增量快照&#xff09;的功能&#xff0c;同时取代了原有的实验性的Parallel Snapshot&#xff08;并行快照&#xff09;。在本篇博客中&#xff0c;我将介绍全新快照方式的原理&#xff0c;以…...

windows下安装composer

安装Php 教程 下载composer 官网 中文网站 exe下载地址 下载好exe 双击运行 找到php.ini注释一行代码 测试 composer -v说明安装成功 修改源 执行以下命令即可修改 composer config -g repo.packagist composer https://packagist.phpcomposer.com # 查看配置…...

企业游学进华秋,助力电子产业创新与发展

近日&#xff0c;淘IC企业游学活动&#xff0c;携20多位电子行业的企业家&#xff0c;走进了深圳华秋电子有限公司&#xff08;以下简称“华秋”&#xff09;&#xff0c;进行交流学习、供需对接。华秋董事长兼CEO陈遂佰对华秋的发展历程、业务版块、产业布局等做了详尽的介绍&…...

玩转Tomcat:从安装到部署

文章目录 一、什么是 Tomcat二、Tomcat 的安装与使用2.1 下载安装2.2 目录结构2.3 启动 Tomcat 三、部署程序到 Tomcat3.1 Windows环境3.2 Linux环境 一、什么是 Tomcat 一看到 Tomcat&#xff0c;我们一般会想到什么&#xff1f;没错&#xff0c;就是他&#xff0c;童年的回忆…...

吃透《西瓜书》第四章 决策树定义与构造、ID3决策树、C4.5决策树、CART决策树

目录 一、基本概念 1.1 什么是信息熵&#xff1f; 1.2 决策树的定义与构造 二、决策树算法 2.1 ID3 决策树 2.2 C4.5 决策树 2.3 CART 决策树 一、基本概念 1.1 什么是信息熵&#xff1f; 信息熵: 熵是度量样本集合纯度最常用的一种指标&#xff0c;代表一个系统中蕴…...

复现宏景eHR存在任意文件上传漏洞(0day)

目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现 一、漏洞描述 北京宏景世纪软件股份有限公司(简称“宏景软件”)自成立以来始终专注于国有企事业单位人力与人才管理数智化(数字化、智能化)产品的研发和应用推广,是中国国有企事业单位人力与人才管理数智…...

unity连接MySQL数据库并完成增删改查

数据存储量比较大时&#xff0c;我就需要将数据存储在数据库中方便使用&#xff0c;尤其是制作管理系统时&#xff0c;它的用处就更大了。 在编写程序前&#xff0c;需要在Assets文件夹中创建plugins文件&#xff0c;将.dll文件导入&#xff0c;文件从百度网盘自取&#xff1a;…...

13个ChatGPT类实用AI工具汇总

在ChatGPT爆火后&#xff0c;各种工具如同雨后春笋一般层出不穷。以下汇总了13种ChatGPT类实用工具&#xff0c;可以帮助学习、教学和科研。 01 / ChatGPT for google/ 一个浏览器插件&#xff0c;可搭配现有的搜索引擎来使用 最大化搜索效率&#xff0c;对搜索体验的提升相…...

1-linux下mysql8.0.33安装

在互联网企业的日常工作/运维中&#xff0c;我们会经常用到mysql数据库&#xff0c;而linux下mysql的安装方式有三种&#xff1a; 1.mysql rpm安装 2.mysql二进制安装 3.mysql源码安装 今天就为大家讲讲linux下mysql8.0.33版本rpm方式的安装。 1.前提 1.1.系统版本 Cent…...

golang反射获取结构体的值和修改值

功能&#xff1a;根据id和反射技术封装 创建和更新人的查询 一、代码二、演示 一、代码 package coryCommonimport ("context""errors""github.com/gogf/gf/v2/container/gvar""github.com/tiger1103/gfast/v3/internal/app/system/dao&qu…...