數據結構Java--8

二叉搜索樹

像上圖這樣滿足,任意一棵子樹左子樹小于該子樹的根結點右子樹大于該子樹的根結點,滿足這樣的條件,則這種樹就被稱為二叉搜索樹。

public class BinarySearchTree {static class TreeNode {public int val;public TreeNode left;public TreeNode right;public TreeNode(int val) {this.val = val;}}public TreeNode root = null;public boolean search(int val) {TreeNode cur = root;while(cur!=null){if(cur.val > val){cur = cur.left;}else if(cur.val < val) {cur = cur.right;}else{return true ;}}return false;}public void insert(int val) {TreeNode node = new TreeNode(val);if(root==null){root=node;return;}TreeNode cur = root;TreeNode parent = null;while(cur!=null){parent = cur;if(cur.val>val){cur=cur.left;}else if(cur.val<val){cur=cur.right;}else{return;}}if(parent.val>val){parent.left = node;}else if(parent.val<val) {parent.right = node;}}public void remove(int val){if(root==null){return;}TreeNode cur = root;TreeNode parent = null;while(cur!=null) {if(cur.val>val){parent=cur;cur=cur.left;}else if(cur.val<val){parent=cur;cur=cur.right;}else{removeNode(parent,cur);}}}private void removeNode(TreeNode parent,TreeNode cur) {if(cur.left == null) {//以cur為根左樹為空的情況if(cur==root){//parent和cur在一起(頂根為要刪除的節點時)root=cur.right;}else if(cur==parent.left){//cur為要刪除元素并且走到了parent左邊,cur左邊為空,把parent的左邊接上cur的右邊parent.left=cur.right;}else{//cur為要刪除元素并且走到了parent右邊,cur左邊為空,把parent的右邊接上cur的右邊parent.right=cur.right;}} else if (cur.right == null) {//以cur為根右樹為空的情況if(cur==root){root=cur.left;}else if(cur==parent.left){parent.left=cur.left;}else{parent.right=cur.left;}}else{//cur左右都不為空的情況************TreeNode targetParent = cur;TreeNode target = cur.left;while(target.right!=null){targetParent = target;target = target.right;}cur.val=target.val;if(target==targetParent.right){targetParent.right=target.left;}else{targetParent.left=target.left;}}}
}

二叉搜索樹的模擬只要遵循二叉搜索樹的特性即可。

單支的二叉搜索樹

如果插入的順序不恰當,二叉搜索樹就會出現只有單支的情況

這樣也屬于二叉搜索樹,但是由于另一半枝沒有放入元素,我們對該種搜索樹進行操作時,效率必然會有所下降。

Map和Set

先了解一下Map和Set的概念,以及兩者的區別。

首先這兩種集合是高效的搜索容器,很適合動態查找,不同于我們以前學過的其他數據結構,那些數據結構進行動態查找都需要不小的時間復雜度。

Map是一種Key-Value模型,kv模型的意思就是,如果你往里面存放數據,那就需要提供key 和 value的值,我們也稱這種模型為鍵值對模型。例如我們要統計某單詞在英語試卷中出現的次數,

<單詞,單詞出現的次數>對應的就是 Key 和 Value

Set是一種Key模型,如果你往里面存放數據,只需要提供一個數據Key,但是Set不允許有重復的數據,所以Set更偏向于去重,查找是否存在目標數據

TreeMap

TreeMap就是結合了剛剛提到的KeyValue模型和搜索樹,實際上TreeMap底層是紅黑樹,現階段還沒學到紅黑樹,這里不細說它的結構

Map<String,Integer> map = new TreeMap<>();
TreeMap<String,Integer> map2 = new TreeMap<>();

創建一個TreeMap有以上兩種格式,推薦使用第一種

Map有幾個核心的方法

public static void main(String[] args) {Map<String,Integer> map = new TreeMap<>();//key value typeTreeMap<String,Integer> map2 = new TreeMap<>();map.put("b",3);map.put("c",2);map.put("v",5);int val = map.getOrDefault("d",-1);//如果存在key就返回key的value,不存在就返回Default(-1)System.out.println(val);val = map.get("c");System.out.println(val);Set<String> set = map.keySet();//收集keyCollection<Integer> collection=map.values();//收集valueSet<Map.Entry<String,Integer>> entries = map.entrySet();//搜索樹上每一個節點放的都是Map.Entryfor (Map.Entry<String,Integer> entry :entries) {System.out.println("key:"+entry.getKey()+" value:"+entry.getValue());}for (Map.Entry<String,Integer> entry :map.entrySet()) {System.out.println(entry.getKey()+entry.getValue());}
}

TreeSet

Set是純Key模型,適合查找存在

    public static void main(String[] args) {Set<String> set = new TreeSet<>();set.add("a");set.add("g");set.add("tq");set.remove("a");boolean flag =set.contains("g");System.out.println(flag);System.out.println(set);}
    public static void main(String[] args) {Set<String> set = new TreeSet<>();set.add("a");set.add("g");set.add("tq");set.add("a");
//        set.remove("a");boolean flag =set.contains("g");System.out.println(flag);System.out.println(set);}

TreeSet的底層也是紅黑樹

哈希表

順序結構以及平衡樹中,元素關鍵碼與其存儲位置之間沒有對應的關系,因此在查找一個元素時,必須要經過關鍵 碼的多次比較。

順序查找時間復雜度為O(N),平衡樹中為樹的高度,即O(log2(N)?),搜索的效率取決于搜索過程中 元素的比較次數。

但是哈希表不一樣,哈希表可以不經過任何比較,一次直接從表中得到要搜索的元素。

沖突

要明白什么是哈希表的沖突之前,不防這樣設想一下,假若有5個數據,他的范圍在1到10之間

這個時候我們不難發現,如果創建一個帶有1到10下標的表格把對應數據存放起來,這樣一來我們將來要找目標數據的時候就會很方便,只需要對應下標就可以找到。

但是如果保持5個數據數量不變的情況下,但是把范圍改變至1到20,并且這個時候我們不能把表進行擴容

假若這個時候指定規則,不管目標數據為個位數還是十位數,數據的個位數是什么我們就放到什么位置,這個時候我們把12放到2下標的位置,表的內容就產生了沖突

哈希函數

針對沖突的發生,又引出了一個概念,哈希函數可以有很多種,舉個常見的,線性函數,比如:? ? ? ? Hash(Key)= A*Key + B ,但是大多數情況下,我們使用除留余數法,函數為:? ? ? ? ? ? ? ? ? ?? ? ? ? Hash(Key)= Key % 表長

負載因子

散列表的負載因子=元素個數/表長,通常來說負載因子越小,沖突的概率越低,就像馬路一樣,如果馬路越寬,那么堵車的可能性也會變低。我們通常擴展列表的長度來使得負載因子擴展,通常情況下,如果負載因子達到了0.75,我們就要對散列表進行擴容

解決沖突

既然有了哈希函數,并且產生了沖突,那我們就要解決沖突,解決沖突可以分為兩種方式,開散列和閉散列。

首先來說說閉散列,閉散列我們通常采用線性探測的方式來解決沖突,按上面的例子來簡單說就是,12得到的結果是2要放在2的位置,但是2已經有了數據,這個時候我們就把12放到下一個為空的位置

這種解決方式雖然簡單粗暴,但是必然會影響查找的時間復雜度,以為增加后續可能發生的沖突

所以我們就要用開散列的方法

哈希桶

哈希表的底層就是哈希桶,哈希桶是什么呢?哈希桶就是在前面我們畫的表格的基礎上,每一個表格都寬展出一個鏈表,使得一個下標能存放更多的數據

public class HashBucket {//哈系桶是哈希查找的關鍵static class Node{public int key;public int value;public Node next;public Node(int key,int value){this.key = key;this.value = value;}}public Node[] array;public int usedSize;public HashBucket() {array = new Node[10];}public void putLast (int key,int value){//尾插法,這里的尾差指的是,在表對應的位置上,對鏈表結構進行尾插int index = key % array.length;Node node = new Node(key,value);if(array[index] == null){//第一次插入array[index] = node;usedSize++;if(loadFactor() >=0.75){resize();}return;}Node cur = array[index];//若不是第一次插入,則進行尾插while(cur.next!=null){//尾插cur = cur.next;}cur.next = node;usedSize++;if(loadFactor() >= 0.75){resize();}}public void putFirst (int key , int value) {int index = key % array.length;Node node = new Node(key,value);Node cur = array[index];//先遍歷一遍鏈表結構,檢查是否存在當前的keywhile(cur!=null){if(cur.key==key){cur.value = value;//若存在當前key,則把當前的value更新掉return;}}node.next = array[index];array[index] = node;usedSize++;if(loadFactor() >= 0.75){resize();}}private double loadFactor() {//算負載因子return usedSize*1.0/array.length;}private void resize(){//如果負載因子大于0.75就對表進行擴容Node[] tempArray = new Node[array.length*2];for (int i = 0; i < array.length; i++) {//遍歷原來的表Node cur = array[i];while(cur != null) {//找到非空的表位Node curNext = cur.next;//先記錄下表位的next,后續會對next進行修改,所以要進行next的備份int newIndex = cur.key % tempArray.length;//算出表位鏈表上的key對應新表的位置,如13%20=13,就找到13位置cur.next = tempArray[newIndex];//頭插到新表里,這樣就把key:13從鏈表中分離出來了tempArray[newIndex] = cur;cur = curNext;//遍歷表位的鏈表}}array=tempArray;//覆蓋舊表}public int get(int key) {int index = key % array.length;Node cur = array[index];while(cur!=null){if(cur.key == key){return cur.value;}cur = cur.next;}return -1;}
}

HashMap

public class TestHashMap {public static void main(String[] args) {Map<String,Integer> map = new HashMap<>();map.put("你好",1);map.put("再見",2);map.put("嗨",3);System.out.println(map.containsKey("你好"));System.out.println(map.containsValue(3));System.out.println(map.get("你好"));System.out.println(map);}
}

和TreeMap的方法種類沒有區別,但是底層結構上有所區別,HashMap的底層是哈希桶(HashBucket),TreeMap的底層是紅黑樹。從先階段的簡單層面來說,可以把HashMap理解成一個兩行的列表

Key和Value的類型可以自己定義,可以是<String,Integer>,也可以是<String,String>,這一點在某些算法中有所體現。

HashSet

public class TestHashSet {public static void main(String[] args) {Set<Integer> set = new HashSet<>();set.add(1);set.add(2);set.add(3);set.add(4);System.out.println(set.contains(2));set.remove(2);System.out.println(set);}
}

相比于TreeSet,HashSet的效率更高,因為HashSet不需要進行額外的數據對比操作,在其他方面基本于TreeSet無異。具體要TreeSet還是HashSet需要結合實際來考慮。

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

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

相關文章

使用Spring Boot和EasyExcel導出Excel文件,并在前端使用Axios進行請求

在現代企業應用中&#xff0c;Excel文件的導出是一項常見且重要的功能。Spring Boot作為Java開發中的熱門框架&#xff0c;結合EasyExcel這樣的高效庫&#xff0c;能夠輕松實現Excel的導出功能。而在前端&#xff0c;使用Axios進行HTTP請求&#xff0c;可以方便地與后端進行數據…

圖論水題5

cf796D 題意 n個點n-1條邊&#xff0c;k個特殊點以及整數d&#xff0c;要求刪除最多的邊保證每個點都可以在d步之內到達一個特殊點&#xff0c;輸入保證每個點都可以在d步內到達特殊點 思路 考慮什么時候可以刪除一條邊&#xff0c;即這條邊連接的兩個點可以在d步內到達兩個不同…

像WPS Office 一樣處理pdf頁面尺寸

1. 修改頁面尺寸import os import shutil import fitz # PyMuPDFdef cm_to_px(cm):# 厘米轉換成像素"""doc fitz.open(input_file)page0 doc[0]width_px page0.mediabox.widthheight page0.mediabox.heightprint(fwidth_px&#xff1a;{width_px} height&a…

Linux 基礎開發工具

在 Linux 環境下進行開發&#xff0c;熟練掌握基礎工具是提升效率、解決問題的核心前提。無論是軟件安裝、代碼編輯&#xff0c;還是編譯調試、版本管理&#xff0c;一套 “趁手” 的工具鏈能讓開發過程事半功倍。本文將從 Linux 開發最核心的七大工具模塊入手&#xff0c;一步…

TapData vs Kafka ETL Pipeline:競爭?共存?——企業實時數據策略的正確打開方式

【引言】企業實時數據流轉&#xff0c;迎來“集成計算”新范式 企業 IT 架構的演進&#xff0c;從最初的數據孤島&#xff0c;到集中式數據倉庫&#xff0c;再到如今的實時數據驅動架構。在這一過程中&#xff0c;數據的集成&#xff08;數據源→目標&#xff09;與數據的計算&…

十九、云原生分布式存儲 CubeFS

十九、云原生分布式存儲 CubeFS 文章目錄十九、云原生分布式存儲 CubeFS1、分布式存儲初識1.1 分布式存儲主要特性1.2 為什么要在K8s上落地存儲平臺1.3 云原生存儲平臺CubeFS介紹1.4 分布式存儲平臺落地架構1.4.1 混合部署1.4.2 獨立部署-基礎設施集群1.5 資源分配建議1.6 硬件…

如何拯救一家瀕臨破產的科技公司?

從谷底爬起&#xff1a;Medium 的生死重生之路 2022年的 Medium&#xff0c;正墜入一個深不見底的深淵。 每月虧損260萬美元&#xff0c;訂閱用戶持續流失——這不是增長&#xff0c;而是在消耗資本。更致命的是內容質量&#xff1a;平臺充斥著“快速致富學”等空洞內容&#x…

數據結構-算法(一)

一、已知無向圖的鄰接矩陣&#xff0c;求無向圖的鄰接表。 &#xff08;1&#xff09;提示&#xff1a;無向圖如下圖(a)所示&#xff0c;已知鄰接矩陣如圖(b)所示&#xff0c;求對應的鄰接表(c)。&#xff08;2&#xff09;請定義void adjMatrix_2_adjList(int b[4][4], AdjLis…

2025年嵌入式通信電源系統品牌有哪些?

現在科技跑得飛快&#xff0c;嵌入式通信電源系統可是越來越吃香了&#xff0c;尤其是在5G、物聯網、智能家居這些熱門地方。這玩意兒不光能讓設備穩穩當當干活兒&#xff0c;還特省電、賊聰明&#xff0c;優勢杠杠的&#xff01;既然大家伙兒都這么需要它&#xff0c;那到了20…

Ubuntu24.04環境下causal_conv1d和mamba_ssm安裝

環境&#xff1a;WSL的Ubuntu24.041.創建conda環境&#xff0c;其中python版本為3.10.132.當前conda環境依次執行下面命令&#xff1a;conda install cudatoolkit11.8 -c nvidia pip install torch2.1.1 torchvision0.16.1 torchaudio2.1.1 -f https://mirrors.aliyun.com/pyto…

Python爬蟲實戰: 爬蟲常用到的技術及方案詳解

爬蟲是獲取網絡數據的重要工具,Python因其豐富的庫生態系統而成為爬蟲開發的首選語言。下面我將詳細介紹Python爬蟲的常用技術和方案。 一、基礎技術棧 1. 請求庫 Requests - 同步HTTP請求庫 import requests# 基本GET請求 response = requests.get(https://httpbin.org/g…

k8s——持久化存儲 PVC

目錄 k8s持久化存儲&#xff1a; PVC 1 k8s PV是什么&#xff1f; 2 k8s PVC是什么&#xff1f; 3 k8s PVC和PV工作原理 4 創建pod&#xff0c;使用pvc作為持久化存儲卷 ?三種回收策略詳解? 1、創建nfs共享目錄 2、如何編寫pv的資源清單文件 3、創建pv 更新資源清單文…

【系統架構設計師】數據庫設計(一):數據庫技術的發展、數據模型、數據庫管理系統、數據庫三級模式

數據庫技術是研究數據庫的結構、存儲、設計、管理和應用的一門軟件學科。 數據庫系統本質上是一個用計算機存儲信息的系統。 數據庫管理系統是位于用戶與操作系統之間的一層數據管理軟件&#xff0c;其基本目標是提供一個可以方便、有效地存取數據庫信息的環境。 數據庫就是信息…

深入理解 Structured Outputs:基于 JSON Schema 的結構化輸出實踐指南

深入理解 Structured Outputs&#xff1a;基于 JSON Schema 的結構化輸出實踐指南 目錄 引言Structured Outputs 概述應用場景與優勢核心用法&#xff1a;結構化響應的獲取功能對比&#xff1a;Structured Outputs 與 JSON 模式典型應用示例鏈式思維&#xff08;Chain of Tho…

大模型應用編排工具Dify之插件探索

1.前言 ? dify 1.x版本以后插件功能豐富了很多&#xff0c;推出的插件市場上有各式各樣的插件&#xff0c;比如 連接數據庫、連接大模型、搜索和 mcp服務等。其中&#xff0c;有一個比較大的改動&#xff0c;模型供應商不再內置&#xff0c;而是通過插件的形式提供。因此&…

ubuntu2204安裝搜狗拼音輸入法

安裝必要的軟件包 sudo apt update sudo apt install fcitx5 fcitx5-chinese-addons fcitx5-config-qt fcitx5-configtool -y安裝搜狗拼音 下載最新 .deb 包&#xff08;官方地址&#xff1a;https://pinyin.sogou.com/linux/&#xff09;&#xff0c;安裝&#xff1a; sudo dp…

三,設計模式-抽象工廠模式

目的 在 工廠模式 中&#xff0c;當需要創建新的產品時&#xff0c;則額外需要創建新的工廠&#xff0c;這種模式是對產品制造方法的抽象化&#xff0c;如果產品種類變多&#xff0c;則工廠數目變多&#xff0c;則代碼規模會越來越大&#xff0c;且不同的產品類的生成依賴不同…

Vue3響應式編程核心:ref與reactive全方位對比

在Vue3的Composition API中&#xff0c;ref和reactive是構建響應式數據的核心工具。許多開發者對它們的選擇存在困惑&#xff1a;何時用ref的.value&#xff1f;何時用reactive的直接訪問&#xff1f;為何解構會丟失響應性&#xff1f;本文從原理、場景到實戰陷阱&#xff0c;為…

Redis實戰-緩存的解決方案(一)

1.什么是緩存緩存就是數據交換的緩存區&#xff0c;是存儲數據的臨時區域&#xff0c;讀寫性能高。瀏覽器會有緩存&#xff0c;tomcat服務器也會有緩存&#xff0c;數據庫也會有緩存&#xff0c;CPU也會有緩存&#xff0c;磁盤也會有緩存&#xff0c;所以說緩存是無處不在的并且…