初識數據結構——Map和Set:哈希表與二叉搜索樹的魔法對決

在這里插入圖片描述
在這里插入圖片描述
?(click)


大家好!我是你們的老朋友——想不明白的過度思考者!今天我們要一起探索Java中兩個神奇的數據結構:Map和Set!準備好了嗎?讓我們開始這場魔法之旅吧!🎩

🎯 先來點開胃菜:二叉搜索樹(BST)

🌳 什么是二叉搜索樹?

想象一下,你有一棵神奇的樹,左邊的果子都比樹根小,右邊的果子都比樹根大!這就是我們的二叉搜索樹!

二叉搜索樹又稱二叉排序樹,它或者是一棵空樹,或者是具有以下性質的二叉樹:

  • 若它的左子樹不為空,則左子樹上所有節點的值都小于根節點的值
  • 若它的右子樹不為空,則右子樹上所有節點的值都大于根節點的值
  • 它的左右子樹也分別為二叉搜索樹
package Tree;//表示樹的節點
class Node {public int key;public Node left;public Node right;public Node(int key) {this.key = key;}@Overridepublic String toString() {return "Node{" +"key=" + key +", left=" + left +", right=" + right +'}';}
}public class BinarySearchTree {private Node root = null;//把新的元素插入到樹中public void insert(int key) {//如果當前是空樹,那就直接用root指向新節點即可Node newNode = new Node(key);if (root == null) {root = newNode;}// 如果是普通的樹,需要找到哦插入位置,再去進行插入//cur用來找待插入元素的位置//parent記錄cur的父元素Node cur = root;Node parent = null;while (cur != null) {if(key<cur.key) {//往左找parent = cur;cur = cur.left;}else if(key>cur.key) {//往右找parent = cur;cur = cur.right;}else {//對于相等的情況,存在不同的解決方式//當前不允許重復key存在,并且是Set只保存key,直接returnreturn;}}//通過上述循環最終得到的結果就是cur為空//此時的parent就是葉子節點,也就是新插入元素的父親,此時就是要把newNode插入到parent的子節點上//新節點,應該在parent的左子樹還是右子樹呢??直接比較大小if (key> parent.key){parent.right = newNode;}else {parent.left = newNode;}}public void remove(int key) {if (root == null) {return;}//查找要刪除節點的位置,記錄其父節點Node cur = root;Node parent = null;while (cur != null) {if(key<cur.key) {parent = cur;cur = cur.left;}else if(key>cur.key) {parent = cur;cur = cur.right;}else {//找到了removeNode(parent, cur);return;}}}private void removeNode(Node parent, Node cur) {//具體刪除節點要考慮四種情況//1.沒有子樹if(cur.right == null && cur.left == null) {//1.1如果cur就是root,需要對root進行調整if(cur == root) {//說明整棵樹只有root一個節點,直接把root設置為空root = null;}//1.2如果cur不是root,同時cur是parent的左子樹if (cur == parent.left) {parent.left = null;return;}//1.3如果cur不是root,同時cur是parent的右子樹if (cur == parent.right) {parent.right = null;return;}//穩妥起見加個returnreturn;}//2.只有左子樹if(cur.left != null && cur.right == null) {//2.1cur為rootif(cur == root){root = cur.left;return;}//2.2cur不為root,且cur是parent的左子樹if (cur == parent.left) {parent.left = cur.left;return;}//2.3cur不為root,且cur是parent的右子樹if (cur == parent.right) {parent.right = cur.left;return;}}//3.只有右子樹if(cur.left == null && cur.right != null) {//3.1只有rootif(cur == root){root = cur.right;return;}//3.2cur不是root,且cur是parent的左子樹if (cur == parent.left) {parent.left = cur.right;return;}//3.3cur不是root,且cur是parent的右子樹if (cur == parent.right) {parent.right = cur.right;return;}}//4.左右都有子樹if(cur.left != null && cur.right != null) {// 這種情況下,不需要考慮 cur 是不是 root的情況,并沒有真正的刪除 cur指向的節點,即使 cur 是 root,也無需修改 root 的指向//因為實際刪除的是“替罪羊節點”//4.1首先需要找到右子樹中的最小值 =>替罪羊,//后續要刪除替罪羊,也順便把替罪羊的父親,記錄一下.Node goat = cur.right;Node goatParent= cur;while (goat.left != null) {goatParent = goat;goat = goat.left;}//循環結束后。goat指向的就是cur右子樹的最左側元素//4.2移花接木,把替罪羊節點的值復制到cur節點中cur.key = goat.key;//4.3真正刪除goat節點,因為goat是沒有左子樹的,讓goatParent直接連上goat的右子樹即可// 即使goat的右子樹也是空也不影響if(goat == goatParent.left){goatParent.left = goat.right;}else {goatParent.right = goat.right;}}}//查找key是否在樹中,如果存在則返回對應節點位置,如果不存在則返回nullprivate Node find(int key) {if (root == null) {return null;}Node cur = root;while (cur != null) {if(key<cur.key) {cur = cur.left;}else if(key>cur.key) {cur = cur.right;}else {//相等,找到了return cur;}}return null;}//先序遍歷private static void preOrder(Node root) {if (root == null) {return;}System.out.print(root.key + " ");preOrder(root.left);preOrder(root.right);}//中序遍歷private static void inOrder(Node root) {if (root == null) {return;}inOrder(root.left);System.out.print(root.key + " ");inOrder(root.right);}public void print(){//先打印先序遍歷System.out.println("先序遍歷結果:");preOrder(root);System.out.println();//在打印中序遍歷System.out.println("中序遍歷結果:");inOrder(root);//有了先序和中序就能夠畫出樹的結構}public static void main(String[] args) {int[] arr = {1, 3, 2, 6, 5, 7, 8, 9, 10, 0};//BinarySearchTree也總被縮寫成BSTBinarySearchTree tree = new BinarySearchTree();//循環插入for(int key: arr){tree.insert(key);}tree.print();System.out.println();System.out.println(tree.find(7));}
}

🎭 BST的表演時刻

操作最佳情況(完全二叉樹)最差情況(單支樹)
查找O(logN)O(N)
插入O(logN)O(N)
刪除O(logN)O(N)

💡 小貼士:Java中的TreeMap和TreeSet就是用紅黑樹(BST的升級版)實現的哦!

🎩 主角登場:Map和Set

🗺? Map:你的萬能字典

Map就像你的通訊錄,名字(Key)對應電話(Value),而且名字不能重復!

Map<String, String> heroNicknames = new HashMap<>();
heroNicknames.put("林沖", "豹子頭");
heroNicknames.put("李逵", "黑旋風");
heroNicknames.put("宋江", "及時雨");// 獲取外號
System.out.println(heroNicknames.get("林沖"));  // 輸出:豹子頭// 遍歷所有英雄
for (Map.Entry<String, String> entry : heroNicknames.entrySet()) {System.out.println(entry.getKey() + "的外號是:" + entry.getValue());
}
  • Tip:使用put方法時:
    若key不同,value相同則新增鍵值對
    若key相同,value不同則為修改對應的value

🎭 Map的兩種實現對比

特性TreeMap(紅黑樹)HashMap(哈希表)
底層結構紅黑樹哈希桶
時間復雜度O(logN)O(1)
是否有序Key有序無序
允許nullKey不能為nullKey和Value都可以為null

🎪 Set:獨一無二的馬戲團

Set就像一個不允許重復演員的馬戲團,每個演員都是獨一無二的!

Set<String> fruitSet = new HashSet<>();
fruitSet.add("蘋果");
fruitSet.add("香蕉");
fruitSet.add("橙子");
fruitSet.add("蘋果");  // 這個不會被添加進去System.out.println(fruitSet.contains("香蕉"));  // 輸出:true
System.out.println(fruitSet.size());          // 輸出:3

🎭 Set的兩種實現對比

特性TreeSet(紅黑樹)HashSet(哈希表)
底層結構紅黑樹哈希桶
時間復雜度O(logN)O(1)
是否有序Key有序無序
允許null不允許允許

🔮 哈希表:數據結構的魔法帽

🎩 哈希函數:魔法咒語

哈希函數就像把名字變成數字的咒語:

int hashCode = "魔法".hashCode();  // 返回一個魔法數字

? 哈希沖突:當兩個咒語撞車了

當不同的Key計算出相同的哈希值,就發生了沖突!我們有幾種解決辦法:

  1. 開放地址法(線性探測/二次探測)

    • 線性探測:h(key) = (h(key) + i) % size
    • 二次探測:h(key) = (h(key) + i2) % size
  2. 鏈地址法(哈希桶)

    • 每個位置放一個鏈表,沖突的元素都掛在鏈表上

🌟 哈希桶實現:我們的魔法實驗室

public class HashBucket {static class Node {int key, value;Node next;public Node(int key, int value) {this.key = key;this.value = value;}}private Node[] array;private int size;private static final double LOAD_FACTOR = 0.75;public HashBucket() {array = new Node[8];size = 0;}public int put(int key, int value) {int index = key % array.length;// 查找key是否已存在for (Node cur = array[index]; cur != null; cur = cur.next) {if (key == cur.key) {int oldValue = cur.value;cur.value = value;return oldValue;}}// 插入新節點Node node = new Node(key, value);node.next = array[index];array[index] = node;size++;// 檢查是否需要擴容if ((double)size / array.length >= LOAD_FACTOR) {resize();}return -1;}private void resize() {Node[] newArray = new Node[array.length * 2];for (int i = 0; i < array.length; i++) {Node next;for (Node cur = array[i]; cur != null; cur = next) {next = cur.next;int index = cur.key % newArray.length;cur.next = newArray[index];newArray[index] = cur;}}array = newArray;}public int get(int key) {int index = key % array.length;for (Node cur = array[index]; cur != null; cur = cur.next) {if (key == cur.key) return cur.value;}return -1;}
}

📊 哈希表性能分析

因素影響
哈希函數設計決定沖突率高低
負載因子通常控制在0.75以下
沖突解決方法影響查找效率和內存使用
擴容機制影響性能和內存使用的平衡

🎯 實戰演練:OJ題目解析

1. 只出現一次的數字

題目:給定一個非空整數數組,除了某個元素只出現一次以外,其余每個元素均出現兩次。找出那個只出現了一次的元素。

魔法解法:使用異或運算的特性!

public int singleNumber(int[] nums) {int result = 0;for (int num : nums) {result ^= num;}return result;
}

2. 寶石與石頭

題目:給定字符串J代表寶石的類型,S代表你擁有的石頭。你想知道你擁有的石頭中有多少是寶石。

魔法解法:使用HashSet!

public int numJewelsInStones(String J, String S) {Set<Character> jewels = new HashSet<>();for (char c : J.toCharArray()) {jewels.add(c);}int count = 0;for (char c : S.toCharArray()) {if (jewels.contains(c)) count++;}return count;
}

🎓 知識總結:思維導圖

在這里插入圖片描述

🎉 結語:選擇你的魔法武器

今天我們一起探索了Map和Set的魔法世界,從二叉搜索樹到哈希表,從TreeMap到HashMap,每個數據結構都有它獨特的魔法特性!

記住:

  • 需要快速查找?選HashMap/HashSet!
  • 需要有序存儲?選TreeMap/TreeSet!
  • 遇到哈希沖突?試試鏈地址法!

希望這篇博客能像魔法一樣幫助你理解這些數據結構!

請添加圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/919736.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/919736.shtml
英文地址,請注明出處:http://en.pswp.cn/news/919736.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Unreal Engine UStaticMeshComponent

UnrealUnreal Engine - UStaticMeshComponent&#x1f3db; 定義&#x1f3db; 類繼承? 關鍵特性?? 常見配置&#x1f6e0;? 使用方法&#x1f4da; 在 C 中使用&#x1f4da; 在藍圖中使用&#x1f3ae; 典型應用場景&#x1f4da; 常見子類與用途&#x1f4dd; 小結Unrea…

demo 汽車之家(渲染-篩選-排序-模塊抽離數據)

效果圖展示&#xff1a;代碼截圖注釋詳情實現筆記總體目標&#xff08;按需求點對照代碼&#xff09;數據模塊化、整體渲染框架、篩選/排序的高亮與行為&#xff0c;全部已在 Index.ets CarData.ets 落地。下面按圖片需求 2~4 點逐條總結&#xff0c;并給出關鍵代碼定位與“為…

雙重機器學習DML介紹

本文參考&#xff1a; [1]文心一言回答&#xff1b; 一、核心原理與數學框架 雙重機器學習&#xff08;Double Machine Learning, DML&#xff09;由Chernozhukov等學者于2018年提出&#xff0c;是一種結合機器學習與傳統計量經濟學的因果推斷框架。其核心目標是在高維數據和非…

【圖像算法 - 21】慧眼識蟲:基于深度學習與OpenCV的農田害蟲智能識別系統

摘要&#xff1a; 在現代農業生產中&#xff0c;病蟲害是影響作物產量和品質的關鍵因素之一。傳統的害蟲識別依賴人工巡查&#xff0c;效率低、成本高且易出錯。本文將介紹如何利用深度學習與OpenCV構建一套高效的農田害蟲智能識別系統。該系統能夠自動識別10類常見農業害蟲&a…

循環神經網絡實戰:GRU 對比 LSTM 的中文情感分析(三)

循環神經網絡實戰&#xff1a;GRU 對比 LSTM 的中文情感分析&#xff08;三&#xff09; 文章目錄循環神經網絡實戰&#xff1a;GRU 對比 LSTM 的中文情感分析&#xff08;三&#xff09;前言數據準備&#xff08;與 LSTM 相同&#xff09;模型搭建&#xff08;GRU&#xff09;…

學習游戲制作記錄(制作提示框以及使用鍵盤切換UI)8.21

1.制作裝備提示框創建提示框&#xff0c;添加文本子對象&#xff0c;用來描述名稱&#xff0c;類型以及屬性加成掛載垂直分配組件和文本大小適配組件&#xff0c;這樣圖像會根據文本大小來調整自己創建UI_ItemTip腳本并掛載在文本框上&#xff1a;[SerializeField] private Tex…

chapter07_初始化和銷毀方法

一、簡介 一個Bean&#xff0c;在進行實例化之后&#xff0c;需要進行兩種初始化 初始化屬性&#xff0c;由PropertyValues進行賦值初始化方法&#xff0c;由ApplicationContext統一調用&#xff0c;例如加載配置文件 Bean的初始化與銷毀&#xff0c;共有三種方式&#xff08;注…

open webui源碼分析6-Function

一、Functions簡介 可以把Tools作為依賴于外部服務的插件&#xff0c;Functions就是內部插件&#xff0c;二者都是用來增強open webui的能力的。Functions是輕量的&#xff0c;高度可定制的&#xff0c;并且是用純Python編寫的&#xff0c;所以你可以自由地創建任何東西——從新…

C2039 “unref“:不是“osgEarth::Symbology::Style”的成員 問題分析及解決方法

在osgEarth2.10中實現多線段連續測量功能時,遇到下圖中的錯誤; 經過測試和驗證,主要問題出現在下圖圈出代碼的定義上 圖22-1 對于22-1中的兩個變量這樣定義是錯誤的。因為Style類沒有繼承自osg::Referenced,因此不能與osg::ref_ptr配合使用

GitHub 熱榜項目 - 日榜(2025-08-19)

GitHub 熱榜項目 - 日榜(2025-08-19) 生成于&#xff1a;2025-08-19 統計摘要 共發現熱門項目&#xff1a;12 個 榜單類型&#xff1a;日榜 本期熱點趨勢總結 本期GitHub熱榜呈現三大技術熱點&#xff1a;1&#xff09;AI原生開發持續爆發&#xff0c;Archon OS、Parlant等…

ingress 配置ssl證書

模擬環境舉例&#xff1a; # 生成帶 OU 的證書配置文件 cat > csr.conf <<EOF [ req ] default_bits 2048 prompt no default_md sha256 distinguished_name dn[ dn ] C CN ST Beijing L Beijing O YourCompany, Inc. # 組織名稱 (必填) OU DevOps De…

Pandas 合并數據集:concat 和 append

文章目錄Pandas 合并數據集&#xff1a;concat 和 append回顧&#xff1a;NumPy 數組的拼接使用 pd.concat 進行簡單拼接重復索引將重復索引視為錯誤忽略索引添加多級索引&#xff08;MultiIndex&#xff09;鍵使用連接&#xff08;Join&#xff09;方式拼接append 方法Pandas …

2025年5月架構設計師綜合知識真題回顧,附參考答案、解析及所涉知識點(七)

本文主要回顧2025年上半年(2025-5-24)系統架構設計師考試上午綜合知識科目的選擇題,同時附帶參考答案、解析和所涉知識點。 2025年5月架構設計師綜合知識真題回顧,附參考答案、解析及所涉知識點(一) 2025年5月架構設計師綜合知識真題回顧,附參考答案、解析及所涉知識點(…

面向RF設計人員的微帶貼片天線計算器

微帶貼片天線和陣列可能是僅次于單極天線和偶極天線的最簡單的天線設計。這些天線也很容易集成到PCB中&#xff0c;因此通常用于5G天線陣列和雷達等高級系統。這些天線陣列在基諧模式和高階模式下也遵循一組簡單的設計方程&#xff0c;因此您甚至可以在不使用仿真工具的情況下設…

明基RD280U編程顯示器深度測評:碼農的「第二塊鍵盤」竟然會發光?

文章目錄前言一、開箱篇&#xff1a;當理工男遇到「俄羅斯套娃式包裝」二、外觀篇&#xff1a;深空灰的「代碼容器」1. 桌面變形記2. 保護肩頸的人體工學設計三、顯示篇&#xff1a;給代碼做「光子嫩膚」1. 28寸超大大屏 3:2屏比 4K超清2.專業編程模式&#xff0c;讓代碼一目…

算法114. 二叉樹展開為鏈表

題目&#xff1a;給你二叉樹的根結點 root &#xff0c;請你將它展開為一個單鏈表&#xff1a; 展開后的單鏈表應該同樣使用 TreeNode &#xff0c;其中 right 子指針指向鏈表中下一個結點&#xff0c;而左子指針始終為 null 。 展開后的單鏈表應該與二叉樹 先序遍歷 順序相同。…

智慧能源管理系統:點亮山東零碳園區的綠色引擎

一、概述在全球積極踐行“雙碳”目標的時代浪潮下&#xff0c;山東作為經濟大省&#xff0c;正全力推動產業的綠色變革&#xff0c;零碳園區建設成為其中的關鍵一環。《山東省零碳園區建設方案》明確規劃&#xff0c;到2027年建成15個左右省級零碳園區 &#xff0c;到2030年進一…

分布式日志分析平臺(ELFK 與 EFK)理論

一、日志分析平臺核心概念在分布式系統中&#xff0c;日志是系統運行狀態監控、問題排查和業務分析的重要依據。隨著系統規模擴大&#xff0c;單機日志管理方式已無法滿足需求&#xff0c;分布式日志分析平臺應運而生。其核心目標是實現日志的集中收集、統一處理、高效存儲和可…

CoreShop微信小程序商城框架開啟多租戶-添加一個WPF客戶端以便進行本地操作--讀取店鋪信息(6)

本節內容&#xff0c;使用登錄的token進行店鋪信息讀取&#xff0c;順利的話&#xff0c;進行EXCEL上傳測試。 1。在后臺編寫 讀取店鋪信息代碼 1.1 查看原來鋪店信息在什么位置&#xff0c;店鋪的表格為CoreCmsStore#region 獲取列表// POST: Api/CoreCmsStore/GetPageList///…

UE5關卡藍圖能不能保存副本呀?

提問 關卡藍圖能不能保存副本呀&#xff1f; 回答 在 UE 里&#xff0c;“關卡藍圖&#xff08;Level Blueprint&#xff09;”本身其實是不能直接復制/保存成獨立資源的&#xff0c;因為它和具體的 **Level&#xff08;.umap 文件&#xff09;**是綁定的——相當于一個“場景腳…