跳躍表可視化深度解析:動態演示數據結構核心原理

跳躍表可視化深度解析:動態演示數據結構核心原理

一、跳躍表基礎概念與核心優勢

跳躍表(SkipList)是一種基于多層索引鏈表的數據結構,通過概率平衡實現高效的插入、刪除和查找操作。其核心優勢體現在:

  1. ?時間復雜度優化?

    • 查找/插入/刪除平均時間復雜度為O(log n),媲美平衡樹但實現更簡單
      • 通過構建多級索引實現快速跳轉,類似二分查找的效果
      • 例如在10億數據中查找,只需約30次比較(log?10?≈29.9)
    • 最壞情況時間復雜度為O(n),但概率極低
      • 當所有元素都集中在頂層時發生,概率為1/(2^n)
  2. ?動態結構特性?

    • 支持動態擴容和元素隨機分布
      • 插入新元素時,通過隨機算法決定其層級(如擲硬幣法)
      • 示例:Redis的有序集合(zset)就采用跳表實現
    • 通過概率算法自動調節層級結構
      • 每個元素有50%概率晉升到上一層
      • 層級高度期望值為log?n,保持平衡
  3. ?有序性保障?

    • 基底層保持元素有序排列
      • 最底層是完整的單向鏈表,存儲所有元素
      • 上層鏈表都是下層的子集,作為快速通道
    • 支持快速范圍查詢和有序遍歷
      • 可以先定位區間起點,然后順序遍歷
      • 應用場景:數據庫索引、內存緩存等需要范圍查詢的場景
  4. ?實現優勢?(補充)

    • 相比平衡樹:
      • 實現簡單(約100行代碼vs數百行)
      • 不需要復雜的旋轉操作
    • 相比哈希表:
      • 保持數據有序性
      • 支持高效的范圍查詢

二、可視化工具核心功能解析

1. 數據結構設計

class SkipListNode {constructor(key, value, level) {this.key = key;        // 節點鍵值this.value = value;    // 存儲數據this.forward = new Array(level + 1).fill(null); // 多層指針}
}class SkipList {constructor() {this.maxLevel = 16;    // 最大層級this.p = 0.5;          // 節點晉升概率this.level = 0;        // 當前最高層級this.header = new SkipListNode(null, null, this.maxLevel); // 頭節點this.size = 0;         // 元素總數}// 隨機生成節點層級randomLevel() {let level = 0;while (Math.random() < this.p && level < this.maxLevel) {level++;}return level;}// 其他核心方法:insert/delete/search
}

2. 可視化實現原理

(1) 分層渲染機制
function renderSkipList() {// 從最高層到第0層逆向渲染for (let level = skiplist.level; level >= 0; level--) {// 創建層級容器const levelDiv = document.createElement('div');// 添加頭節點標識const headerNode = document.createElement('div');headerNode.className = 'node header-node';headerNode.textContent = 'HEAD';// 渲染當前層所有節點let current = skiplist.header.forward[level];while (current) {const node = document.createElement('div');node.className = `node level-${level % 5}`; // 按層級著色node.textContent = `${current.key}:${current.value}`;levelDiv.appendChild(node);current = current.forward[level];}visualization.appendChild(levelDiv);}
}
(2) 動態交互功能
  • ?路徑高亮?:搜索時實時標記訪問路徑
  • ?動畫演示?:插入/刪除操作時的節點變化過程
  • ?狀態監控?:實時顯示元素數量、最大層級和內存占用

三、核心操作流程演示

1. 插入操作流程

AppSkipListVisualizer插入(key=3, value=A)生成隨機層級(3層)更新各層指針觸發重繪動態添加新節點AppSkipListVisualizer

2. 搜索路徑追蹤

async function searchAndHighlight(key) {// 重置所有節點樣式document.querySelectorAll('.node').forEach(node => {node.classList.remove('visited', 'found');});let current = skiplist.header;const path = [];// 從最高層開始搜索for (let i = skiplist.level; i >= 0; i--) {while (current.forward[i] && current.forward[i].key < key) {path.push(current.forward[i]); // 記錄路徑節點current = current.forward[i];}}// 最終定位目標節點current = current.forward[0];if (current.key === key) {path.push(current); // 添加目標節點到路徑highlightPath(path); // 觸發高亮動畫}
}

3. 刪除操作實現

function deleteNode(key) {const update = new Array(this.maxLevel + 1).fill(null);let current = this.header;// 定位前驅節點for (let i = this.level; i >= 0; i--) {while (current.forward[i] && current.forward[i].key < key) {update[i] = current;current = current.forward[i];}}// 更新指針關系current = current.forward[0];if (current.key === key) {for (let i = 0; i <= this.level; i++) {if (update[i].forward[i] !== current) break;update[i].forward[i] = current.forward[i];}// 自動降級處理while (this.level > 0 && this.header.forward[this.level] === null) {this.level--;}}
}

四、性能監控與優化

1. 狀態監控面板

監控指標實現原理優化價值
元素數量實時統計鏈表節點總數預估內存占用
最大層級動態跟蹤最高有效索引層評估概率平衡效果
內存占用計算節點指針和鍵值存儲總量優化存儲結構設計

2. 可視化性能優化

  1. ?虛擬滾動?:只渲染可視區域內的節點
  2. ?批量更新?:合并多個DOM操作減少重繪
  3. ?內存回收?:及時清理無效節點引用

五、應用場景與擴展

1. 典型應用場景

  • ?數據庫索引?:MySQL的InnoDB存儲引擎使用類似結構優化索引查詢
  • ?緩存系統?:Redis的Sorted Set實現依賴跳表結構
  • ?實時排行榜?:游戲積分系統的快速排名查詢

2. 擴展功能建議

  1. ?持久化存儲?:增加localStorage數據持久化功能
  2. ?分布式擴展?:模擬多節點跳表集群
  3. ?性能對比?:與紅黑樹、B+樹的可視化對比

完整代碼

<!DOCTYPE html>
<html lang="zh-CN" data-theme="light">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>跳躍表(SkipList)可視化演示</title><script src="https://cdn.tailwindcss.com"></script><link href="https://cdn.bootcdn.net/ajax/libs/daisyui/4.12.10/full.min.css" rel="stylesheet"><style>.node {position: relative;display: inline-block;margin: 0 5px;padding: 8px 12px;border-radius: 4px;background-color: #3b82f6;color: white;font-weight: bold;box-shadow: 0 2px 4px rgba(0,0,0,0.1);}.node::after {content: "";position: absolute;right: -10px;top: 50%;transform: translateY(-50%);width: 10px;height: 2px;background-color: #6b7280;}.node:last-child::after {display: none;}.level-0 { background-color: #3b82f6; }.level-1 { background-color: #10b981; }.level-2 { background-color: #f59e0b; }.level-3 { background-color: #ef4444; }.level-4 { background-color: #8b5cf6; }.header-node {background-color: #1f2937;color: white;}.path-node {background-color: #fbbf24;border: 2px solid #d97706;}.arrow {display: inline-block;width: 20px;height: 2px;background-color: #6b7280;margin: 0 5px;vertical-align: middle;}</style>
</head>
<body class="min-h-screen bg-gray-100 p-8"><div class="max-w-6xl mx-auto"><div class="card bg-base-100 shadow-xl"><div class="card-body"><h1 class="text-3xl font-bold text-center mb-6">跳躍表(SkipList)可視化演示</h1><!-- 操作面板 --><div class="bg-base-200 p-6 rounded-lg mb-8"><h2 class="text-xl font-semibold mb-4">操作面板</h2><div class="grid grid-cols-1 md:grid-cols-3 gap-4"><div><label class="label"><span class="label-text">鍵(Key)</span></label><input type="text" id="keyInput" placeholder="輸入鍵" class="input input-bordered w-full"></div><div><label class="label"><span class="label-text">值(Value)</span></label><input type="text" id="valueInput" placeholder="輸入值" class="input input-bordered w-full"></div><div class="flex items-end gap-2"><button id="insertBtn" class="btn btn-primary flex-1">插入</button><button id="updateBtn" class="btn btn-warning flex-1">更新</button><button id="deleteBtn" class="btn btn-error flex-1">刪除</button><button id="searchBtn" class="btn btn-info flex-1">查找</button></div></div><div class="mt-4"><button id="randomBtn" class="btn btn-outline btn-sm">隨機插入10個元素</button><button id="clearBtn" class="btn btn-outline btn-error btn-sm ml-2">清空跳躍表</button></div></div><!-- 可視化展示區 --><div class="bg-base-200 p-6 rounded-lg mb-8"><h2 class="text-xl font-semibold mb-4">跳躍表結構可視化</h2><div id="visualization" class="bg-white p-4 rounded-lg overflow-x-auto"><div id="skiplistContainer" class="flex flex-col-reverse gap-8"></div></div></div><!-- 狀態信息區 --><div class="bg-base-200 p-6 rounded-lg"><h2 class="text-xl font-semibold mb-4">狀態信息</h2><div class="stats shadow"><div class="stat"><div class="stat-title">當前元素數量</div><div id="sizeDisplay" class="stat-value">0</div></div><div class="stat"><div class="stat-title">當前最高層級</div><div id="levelDisplay" class="stat-value">0</div></div><div class="stat"><div class="stat-title">估算內存占用</div><div id="memoryDisplay" class="stat-value">0 B</div></div></div><div class="mt-4"><div class="overflow-x-auto"><table class="table table-zebra"><thead><tr><th>鍵(Key)</th><th>值(Value)</th></tr></thead><tbody id="itemsTable"><!-- 鍵值對將在這里動態生成 --></tbody></table></div></div></div><!-- 搜索路徑展示區 --><div class="bg-base-200 p-6 rounded-lg"><h2 class="text-xl font-semibold mb-4">搜索路徑</h2><div id="pathContainer" class="bg-white p-4 rounded-lg"><div class="flex flex-wrap gap-2" id="pathNodes"><!-- 路徑節點將在這里動態生成 --></div></div></div></div></div></div><script>class SkipListNode {constructor(key, value, level) {this.key = key;this.value = value;this.forward = new Array(level + 1).fill(null);}}class SkipList {constructor(maxLevel = 16, p = 0.5) {this.maxLevel = maxLevel;this.p = p;this.level = 0;this.header = new SkipListNode(null, null, this.maxLevel);this.size = 0;}randomLevel() {let level = 0;while (Math.random() < this.p && level < this.maxLevel) {level++;}return level;}insert(key, value) {const update = new Array(this.maxLevel + 1).fill(null);let current = this.header;for (let i = this.level; i >= 0; i--) {while (current.forward[i] && current.forward[i].key < key) {current = current.forward[i];}update[i] = current;}current = current.forward[0];if (current && current.key === key) {current.value = value;return false; // 表示更新而非插入}const newLevel = this.randomLevel();if (newLevel > this.level) {for (let i = this.level + 1; i <= newLevel; i++) {update[i] = this.header;}this.level = newLevel;}const newNode = new SkipListNode(key, value, newLevel);for (let i = 0; i <= newLevel; i++) {newNode.forward[i] = update[i].forward[i];update[i].forward[i] = newNode;}this.size++;return true; // 表示插入而非更新}search(key) {let current = this.header;for (let i = this.level; i >= 0; i--) {while (current.forward[i] && current.forward[i].key < key) {current = current.forward[i];}}current = current.forward[0];if (current && current.key === key) {return current.value;}return null;}delete(key) {const update = new Array(this.maxLevel + 1).fill(null);let current = this.header;for (let i = this.level; i >= 0; i--) {while (current.forward[i] && current.forward[i].key < key) {current = current.forward[i];}update[i] = current;}current = current.forward[0];if (!current || current.key !== key) {return false;}for (let i = 0; i <= this.level; i++) {if (update[i].forward[i] !== current) {break;}update[i].forward[i] = current.forward[i];}while (this.level > 0 && this.header.forward[this.level] === null) {this.level--;}this.size--;return true;}estimateSize() {let totalBytes = 0;let current = this.header.forward[0];while (current) {totalBytes += current.key.length + JSON.stringify(current.value).length;totalBytes += 8 * current.forward.length;current = current.forward[0];}return totalBytes;}items() {const result = [];let current = this.header.forward[0];while (current) {result.push({ key: current.key, value: current.value });current = current.forward[0];}return result;}}// 初始化跳躍表const skiplist = new SkipList();const visualization = document.getElementById('skiplistContainer');const sizeDisplay = document.getElementById('sizeDisplay');const levelDisplay = document.getElementById('levelDisplay');const memoryDisplay = document.getElementById('memoryDisplay');const itemsTable = document.getElementById('itemsTable');const keyInput = document.getElementById('keyInput');const valueInput = document.getElementById('valueInput');// 渲染跳躍表function renderSkipList() {visualization.innerHTML = '';// 從最高層開始渲染for (let level = skiplist.level; level >= 0; level--) {const levelDiv = document.createElement('div');levelDiv.className = 'flex items-center';// 添加層級標簽const levelLabel = document.createElement('div');levelLabel.className = 'w-16 text-right pr-4 font-bold';levelLabel.textContent = `L${level}`;levelDiv.appendChild(levelLabel);// 添加頭節點const headerNode = document.createElement('div');headerNode.className = 'node header-node';headerNode.textContent = 'HEAD';levelDiv.appendChild(headerNode);// 添加箭頭const arrow = document.createElement('div');arrow.className = 'arrow';levelDiv.appendChild(arrow);// 添加該層的所有節點let current = skiplist.header.forward[level];while (current) {const node = document.createElement('div');node.className = `node level-${level % 5}`;node.textContent = `${current.key}:${current.value}`;levelDiv.appendChild(node);// 如果不是最后一個節點,添加箭頭if (current.forward[level]) {const arrow = document.createElement('div');arrow.className = 'arrow';levelDiv.appendChild(arrow);}current = current.forward[level];}visualization.appendChild(levelDiv);}// 更新狀態信息sizeDisplay.textContent = skiplist.size;levelDisplay.textContent = skiplist.level;memoryDisplay.textContent = formatBytes(skiplist.estimateSize());// 更新鍵值對表格updateItemsTable();}function formatBytes(bytes) {if (bytes === 0) return '0 B';const k = 1024;const sizes = ['B', 'KB', 'MB', 'GB'];const i = Math.floor(Math.log(bytes) / Math.log(k));return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];}function updateItemsTable() {itemsTable.innerHTML = '';const items = skiplist.items();items.forEach(item => {const row = document.createElement('tr');row.innerHTML = `<td>${item.key}</td><td>${item.value}</td>`;itemsTable.appendChild(row);});}// 查找并高亮顯示路徑async function searchAndHighlight(key) {// 重置所有節點樣式document.querySelectorAll('.node').forEach(node => {node.classList.remove('visited', 'found', 'path-node');});let current = skiplist.header;const searchSteps = [];const path = [{key: 'HEAD', level: skiplist.level}]; // 初始化路徑,頭節點// 從最高層開始查找for (let i = skiplist.level; i >= 0; i--) {while (current.forward[i] && current.forward[i].key < key) {searchSteps.push({level: i,node: current.forward[i],action: '向右移動'});// 記錄路徑節點(包含層級)path.push({key: current.forward[i].key,level: i});// 高亮顯示當前節點const nodeElements = document.querySelectorAll(`.node.level-${i % 5}`);for (const el of nodeElements) {if (el.textContent.includes(`${current.forward[i].key}:`)) {el.classList.add('visited');await new Promise(resolve => setTimeout(resolve, 800));break;}}current = current.forward[i];}searchSteps.push({level: i,node: current,action: '向下移動'});// 記錄當前節點(向下移動時)if (current !== skiplist.header) {path.push({key: current.key,level: i});}// 如果不是頭節點,高亮顯示if (current !== skiplist.header) {const nodeElements = document.querySelectorAll(`.node.level-${i % 5}`);for (const el of nodeElements) {if (el.textContent.includes(`${current.key}:`)) {el.classList.add('visited');await new Promise(resolve => setTimeout(resolve, 500));break;}}}}current = current.forward[0];if (current && current.key === key) {// 記錄目標節點(層級為0)path.push({key: current.key,level: 0});// 高亮顯示找到的節點const nodeElements = document.querySelectorAll('.node');for (const el of nodeElements) {if (el.textContent.includes(`${current.key}:`)) {el.classList.add('found');break;}}return { found: true, value: current.value, steps: searchSteps, path: path };}return { found: false, steps: searchSteps, path: path };}// 渲染搜索路徑function renderSearchPath(path) {const pathContainer = document.getElementById('pathNodes');pathContainer.innerHTML = '';pathContainer.className = 'flex flex-wrap items-center gap-4'; // 優化布局path.forEach((node, index) => {const nodeContainer = document.createElement('div');nodeContainer.className = 'flex flex-col items-center';// 添加層級標簽const levelLabel = document.createElement('div');levelLabel.className = 'text-xs font-bold bg-gray-200 px-1 rounded mb-1';levelLabel.textContent = `L${node.level}`;nodeContainer.appendChild(levelLabel);// 添加節點const nodeElement = document.createElement('div');nodeElement.className = 'node path-node';if (node.key === 'HEAD') {nodeElement.classList.add('header-node');nodeElement.textContent = 'HEAD';} else {nodeElement.textContent = node.key;}nodeContainer.appendChild(nodeElement);pathContainer.appendChild(nodeContainer);// 添加箭頭(除最后一個節點外)if (index < path.length - 1) {const arrow = document.createElement('div');arrow.className = 'arrow';arrow.style.width = '30px';arrow.style.height = '2px';arrow.style.background = '#6b7280';pathContainer.appendChild(arrow);}});}// 事件監聽document.getElementById('searchBtn').addEventListener('click', async () => {const key = keyInput.value.trim();if (!key) {alert('請輸入要查找的鍵');return;}const result = await searchAndHighlight(key);// 渲染搜索路徑renderSearchPath(result.path);if (result.found) {alert(`找到鍵 "${key}",對應的值為: ${result.value}`);} else {alert(`未找到鍵 "${key}"`);}});document.getElementById('insertBtn').addEventListener('click', () => {const key = keyInput.value.trim();const value = valueInput.value.trim();if (!key) {alert('請輸入鍵');return;}skiplist.insert(key, value);renderSkipList();keyInput.value = '';valueInput.value = '';keyInput.focus();});document.getElementById('updateBtn').addEventListener('click', () => {const key = keyInput.value.trim();const value = valueInput.value.trim();if (!key) {alert('請輸入鍵');return;}if (skiplist.search(key) === null) {alert('鍵不存在,無法更新');return;}skiplist.insert(key, value);renderSkipList();keyInput.value = '';valueInput.value = '';keyInput.focus();});document.getElementById('deleteBtn').addEventListener('click', () => {const key = keyInput.value.trim();if (!key) {alert('請輸入鍵');return;}if (skiplist.delete(key)) {renderSkipList();} else {alert('鍵不存在,無法刪除');}keyInput.value = '';valueInput.value = '';keyInput.focus();});document.getElementById('randomBtn').addEventListener('click', () => {const randomWords = ['apple', 'banana', 'cherry', 'date', 'elderberry', 'fig', 'grape', 'honeydew', 'kiwi', 'lemon','mango', 'nectarine', 'orange', 'pear', 'quince','raspberry', 'strawberry', 'tangerine', 'watermelon'];for (let i = 0; i < 10; i++) {const randomKey = randomWords[Math.floor(Math.random() * randomWords.length)];const randomValue = Math.floor(Math.random() * 100);skiplist.insert(randomKey, randomValue);}renderSkipList();});document.getElementById('clearBtn').addEventListener('click', () => {skiplist = new SkipList();renderSkipList();});// 初始渲染renderSkipList();</script>
</body>
</html>

git: https://gitcode.com/weixin_44778145/lsm_demo/blob/main/skiplist_demo.html

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

總結

通過本文的可視化實現,我們深入理解了跳躍表概率平衡多層索引的核心思想。這種數據結構在需要高效動態操作的場景中具有獨特優勢,其可視化實現方式也為算法教學和性能分析提供了新的思路。建議開發者結合實際業務場景,靈活運用跳躍表解決復雜的數據結構問題。

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

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

相關文章

《Sentinel服務保護實戰:控制臺部署與SpringCloud集成指南》

sentinel 介紹 Sentinel是阿里巴巴開源的一款服務保護框架&#xff0c;目前已經加入SpringCloudAlibaba中。官方網站&#xff1a; home | Sentinel Sentinel 的使用可以分為兩個部分: 核心庫&#xff08;Jar包&#xff09;&#xff1a;不依賴任何框架/庫&#xff0c;能夠運行…

IBM Watsonx BI:AI賦能的下一代商業智能平臺

產品概覽 IBM Watsonx BI 是基于 watsonx 企業級 AI 與數據平臺 構建的智能分析解決方案&#xff0c;專為現代化企業打造。它深度融合人工智能技術&#xff0c;突破傳統 BI 工具的限制&#xff0c;通過自動化數據洞察、自然語言交互和預測分析&#xff0c;幫助企業在復雜數據環…

Python實現GO鵝優化算法優化GBRT漸進梯度回歸樹回歸模型項目實戰

說明&#xff1a;這是一個機器學習實戰項目&#xff08;附帶數據代碼文檔&#xff09;&#xff0c;如需數據代碼文檔可以直接到文章最后關注獲取 或者私信獲取。 1.項目背景 隨著大數據和人工智能技術的快速發展&#xff0c;回歸預測在金融、氣象、能源等多個領域中扮演著至關…

深度學習計算(深度學習-李沐-學習筆記)

層和塊 單一輸出的線性模型&#xff1a;單個神經網絡 &#xff08;1&#xff09;接受一些輸入&#xff1b; &#xff08;2&#xff09;生成相應的標量輸出&#xff1b; &#xff08;3&#xff09;具有一組相關 參數&#xff08;parameters&#xff09;&#xff0c;更新這些參數…

leetcode熱題——搜索二維矩陣Ⅱ

目錄 搜索二維矩陣Ⅱ 題目描述 題解 解法一&#xff1a;暴力搜索 C 代碼實現 復雜度分析 解法二&#xff1a;二分查找 C 代碼實現 復雜度分析 解法三&#xff1a;Z字形查找 算法核心思想 算法步驟詳解 C 代碼實現 復雜度分析 搜索二維矩陣Ⅱ 題目描述 編寫一個…

牛客 - 數組中的逆序對

描述 在數組中的兩個數字&#xff0c;如果前面一個數字大于后面的數字&#xff0c;則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。并將P對1000000007取模的結果輸出。 即輸出P mod 1000000007 數據范圍&#xff1a; 對于 50% 的數據, size≤104 s…

Linux 日志管理與時鐘同步詳解

Linux 日志管理與時鐘同步詳解 一、日志管理 1. 日志服務概述 Linux 系統中主要有兩種日志服務&#xff0c;分別負責臨時和永久日志的管理&#xff1a; systemd-journald&#xff1a;存儲臨時日志&#xff0c;服務器重啟后日志會丟失&#xff0c;無需手動配置rsyslog&#xff1…

個人如何做股指期貨?

本文主要介紹個人如何做股指期貨&#xff1f;個人參與股指期貨交易需要遵循一定的流程和規則&#xff0c;同時需充分了解其高風險、高杠桿的特點&#xff0c;并做好風險管理。個人如何做股指期貨&#xff1f;一、了解股指期貨基礎股指期貨是以股票價格指數為標的物的金融期貨合…

設計模式-單例模式 Java

模式概述 單例模式&#xff08;Singleton Pattern&#xff09;是設計模式中最基礎但應用最廣泛的創建型模式之一&#xff0c;確保一個類僅有一個實例&#xff0c;并提供一個全局訪問點。這種模式在需要全局唯一對象的場景中至關重要&#xff0c;如配置管理、線程池、數據庫連接…

RFID 系統行業前沿洞察:技術躍遷與生態重構

在物聯網與人工智能深度融合的時代&#xff0c;RFID&#xff08;射頻識別&#xff09;系統正經歷從 “單品識別工具” 到 “智能決策中樞” 的范式轉變。這一技術憑借其非接觸式數據采集、環境適應性強、全生命周期追溯等特性&#xff0c;在醫療、制造、農業、環保等領域引發連…

實現implements InitializingBean, DisposableBean 有什么用

在 Spring 框架中&#xff0c;實現 InitializingBean 和 DisposableBean 接口用于管理 Bean 的生命周期回調&#xff0c;分別控制 Bean 的初始化后和銷毀前行為。具體作用如下&#xff1a;1. InitializingBean 接口public interface InitializingBean {void afterPropertiesSet…

GitLab 18.2 發布幾十項與 DevSecOps 有關的功能,可升級體驗【一】

沿襲我們的月度發布傳統&#xff0c;極狐GitLab 發布了 18.2 版本&#xff0c;該版本帶來了議題和任務的自定義工作流狀態、新的合并請求主頁、新的群組概覽合規儀表盤、下載安全報告的 PDF 導出文件、中心化的安全策略管理&#xff08;Beta&#xff09;等幾十個重點功能的改進…

如何快速把Clickhouse數據同步到Mysql

直接使用Clickhouse官方支持的Mysql引擎表的方式&#xff01; 一、首先創建Mysql引擎表&#xff1a; CREATE TABLE saas_analysis.t_page_view_new_for_write (id Int64,shop_id Nullable(Int64),session_id Nullable(String),client_id Nullable(String),one_id Nullable(Str…

Kafka 重復消費與 API 冪等消費解決方案

Kafka 是一個高性能的分布式消息系統&#xff0c;但消費者重啟、偏移量&#xff08;offset&#xff09;未正確提交或網絡問題可能導致重復消費。API 冪等性設計則用于防止重復操作帶來的副作用。本文從 Kafka 重復消費和 API 冪等性兩個方面提供解決方案&#xff0c;重點深入探…

win11推遲更新

1、按住WINR2、輸入以下命令&#xff1a;reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" /v FlightSettingsMaxPauseDays /t reg_dword /d 10000 /f3、點擊確定4、打開搜索框5、在搜索框里邊輸入更新&#xff0c;選擇檢查更新6、在暫停…

【uniapp】---- 使用 uniapp 實現視頻和圖片上傳且都可以預覽展示

1. 前言 接手得 uniapp 開發的微信小程序項目,新的開發需求是需要同時上傳圖片和視頻,但是之前的上傳都沒有進行封裝,都是每個頁面需要的時候單獨實現,現在新的需求,有多個地方都需要上傳圖片、視頻或語音等,這樣就需要封裝一個組件,然后發現部分地方使用了 uni-file-p…

(nice!!!) (LeetCode 每日一題) 2411. 按位或最大的最小子數組長度(位運算+滑動窗口)

2411. 按位或最大的最小子數組長度 思路&#xff1a;位運算滑動窗口&#xff0c;時間復雜度0(n*32)。 **遍歷每一個元素nums[i]&#xff0c;然后看能否改變它前面的元素nums[j]&#xff08; j<i &#xff09;&#xff0c; 當(nums[j]|nums[i])nums[j]時&#xff0c;說明當前…

算法競賽階段二-數據結構(36)數據結構雙向鏈表模擬實現

//#include<bits/stdc.h> #include<iostream> using namespace std; const int N1e510; //定義 int e[N],pre[N],ne[N],h,id; int mp[N]; //頭插 // 兵 y // x void push_front (int x) {id;e[id]x;mp[x]id;pre[id]h;ne[id]ne[h];//先修改新節點…

津發科技帶你了解皮膚電信號中的SCL與SCR

皮膚電&#xff08;Electrodermal Activity, EDA&#xff09;作為一種非常容易獲取的基本生理信號&#xff0c;可以很好地量化我們的情緒反應&#xff0c;被廣泛應用于情感識別研究中。它代表機體受到刺激時皮膚電傳導的變化。皮膚電反應作為交感神經系統功能的直接指標&#x…

spark的broadcast variables

在 Spark 中&#xff0c;廣播變量&#xff08;Broadcast Variables&#xff09; 是一種特殊類型的共享變量&#xff0c;用于高效地在集群中的所有節點間分發大型只讀數據集。它解決了 Spark 任務中頻繁傳輸重復數據的性能問題&#xff0c;特別適用于需要在多個任務中重用相同數…