Files
test-repo/docs/.vitepress/theme/components/appendix/computer-fundamentals/HashTableDemo.vue
T
2026-02-24 00:18:09 +08:00

451 lines
9.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="hash-table-demo">
<div class="demo-header">
<span class="title">哈希表超快的查找</span>
<span class="subtitle">通过关键词直接找到数据</span>
</div>
<div class="analogy-box">
<div class="analogy-icon">📚</div>
<div class="analogy-text">
哈希表就像图书馆的<strong>索引卡片</strong>不用在一排排书架上找直接查索引就能找到书的位置
</div>
</div>
<div class="hash-visual">
<div class="input-section">
<div class="section-title">存储数据</div>
<div class="input-group">
<input
v-model="newKey"
type="text"
placeholder="键 (如: apple)"
class="hash-input"
/>
<input
v-model="newValue"
type="text"
placeholder="值 (如: 苹果)"
class="hash-input"
/>
<button class="add-btn" @click="addData">添加</button>
</div>
</div>
<div class="hash-process">
<div class="process-title">哈希过程</div>
<div class="process-diagram">
<div class="process-step">
<div class="step-label">输入键</div>
<div class="step-box">{{ exampleKey }}</div>
</div>
<div class="process-arrow"></div>
<div class="process-step">
<div class="step-label">哈希函数</div>
<div class="step-box func">hash(key) % 10</div>
</div>
<div class="process-arrow"></div>
<div class="process-step">
<div class="step-label">数组索引</div>
<div class="step-box index">{{ exampleIndex }}</div>
</div>
</div>
</div>
<div class="hash-table-display">
<div class="section-title">哈希表</div>
<div class="table-slots">
<div
v-for="(slot, index) in hashTable"
:key="index"
:class="[
'table-slot',
{ occupied: slot !== null, highlighted: index === exampleIndex }
]"
>
<div class="slot-index">{{ index }}</div>
<div class="slot-value">{{ slot || '空' }}</div>
</div>
</div>
</div>
</div>
<div class="performance-comparison">
<div class="comparison-title">性能对比</div>
<div class="comparison-grid">
<div class="comparison-item">
<div class="item-label">哈希表查找</div>
<div class="item-value excellent">O(1)</div>
<div class="item-desc">瞬间找到</div>
</div>
<div class="comparison-item">
<div class="item-label">数组查找</div>
<div class="item-value good">O(n)</div>
<div class="item-desc">需要遍历</div>
</div>
<div class="comparison-item">
<div class="item-label">二分查找</div>
<div class="item-value better">O(log n)</div>
<div class="item-desc">需要排序</div>
</div>
</div>
</div>
<div class="applications">
<div class="app-title">常见应用</div>
<div class="app-list">
<div class="app-item">
<span class="app-icon">👤</span>
<div class="app-text">用户信息表用户ID 用户资料</div>
</div>
<div class="app-item">
<span class="app-icon">🛒</span>
<div class="app-text">购物车商品ID 数量</div>
</div>
<div class="app-item">
<span class="app-icon">📝</span>
<div class="app-text">缓存系统URL 网页内容</div>
</div>
<div class="app-item">
<span class="app-icon">🔍</span>
<div class="app-text">字典单词 释义</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const newKey = ref('')
const newValue = ref('')
const exampleKey = ref('apple')
const hashTable = ref([
null,
null,
null,
null,
null,
null,
null,
null,
null,
null
])
// 初始化一些数据
const initData = () => {
const data = [
{ key: 'apple', value: '苹果' },
{ key: 'banana', value: '香蕉' },
{ key: 'orange', value: '橙子' }
]
data.forEach((item) => {
const index = simpleHash(item.key)
hashTable.value[index] = `${item.key}: ${item.value}`
})
}
const simpleHash = (key) => {
let hash = 0
for (let i = 0; i < key.length; i++) {
hash += key.charCodeAt(i)
}
return hash % 10
}
const exampleIndex = computed(() => simpleHash(exampleKey.value))
const addData = () => {
if (newKey.value && newValue.value) {
const index = simpleHash(newKey.value)
hashTable.value[index] = `${newKey.value}: ${newValue.value}`
newKey.value = ''
newValue.value = ''
}
}
initData()
</script>
<style scoped>
.hash-table-demo {
border: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg-soft);
border-radius: 12px;
padding: 1.5rem;
margin: 1.5rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.demo-header .title {
font-weight: 700;
font-size: 1.1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.9rem;
}
.analogy-box {
display: flex;
gap: 1rem;
padding: 1rem;
background: var(--vp-c-bg);
border-left: 4px solid var(--vp-c-brand);
border-radius: 6px;
margin-bottom: 2rem;
}
.analogy-icon {
font-size: 2rem;
flex-shrink: 0;
}
.analogy-text {
font-size: 0.9rem;
line-height: 1.6;
}
.hash-visual {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
margin-bottom: 2rem;
}
@media (max-width: 768px) {
.hash-visual {
grid-template-columns: 1fr;
}
}
.section-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.input-group {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.hash-input {
padding: 0.75rem;
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
font-size: 0.9rem;
}
.add-btn {
padding: 0.75rem;
background: var(--vp-c-brand);
color: white;
border: none;
border-radius: 6px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
.add-btn:hover {
transform: translateY(-2px);
}
.process-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.process-diagram {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.75rem;
}
.process-step {
text-align: center;
}
.step-label {
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.step-box {
padding: 0.75rem 1.5rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
font-size: 0.9rem;
font-weight: 600;
}
.step-box.func {
background: var(--vp-c-brand-soft);
border-color: var(--vp-c-brand);
color: var(--vp-c-brand);
}
.step-box.index {
background: #10b981;
border-color: #10b981;
color: white;
}
.process-arrow {
font-size: 1.5rem;
color: var(--vp-c-text-2);
}
.hash-table-display {
grid-column: 1 / -1;
}
.table-slots {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 0.75rem;
}
.table-slot {
text-align: center;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 2px solid var(--vp-c-divider);
border-radius: 6px;
}
.table-slot.occupied {
background: var(--vp-c-brand-soft);
border-color: var(--vp-c-brand);
}
.table-slot.highlighted {
border-color: #10b981;
background: rgba(16, 185, 129, 0.1);
}
.slot-index {
font-size: 0.75rem;
color: var(--vp-c-text-2);
margin-bottom: 0.35rem;
}
.slot-value {
font-size: 0.85rem;
font-weight: 600;
}
.performance-comparison {
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 2rem;
}
.comparison-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.comparison-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
}
.comparison-item {
text-align: center;
padding: 1rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.item-label {
font-size: 0.85rem;
color: var(--vp-c-text-2);
margin-bottom: 0.5rem;
}
.item-value {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 0.35rem;
}
.item-value.excellent {
color: #10b981;
}
.item-value.good {
color: var(--vp-c-brand);
}
.item-value.better {
color: #f59e0b;
}
.item-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
}
.applications {
border-top: 1px solid var(--vp-c-divider);
padding-top: 1.5rem;
}
.app-title {
font-weight: 600;
font-size: 1rem;
margin-bottom: 1rem;
color: var(--vp-c-brand);
}
.app-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 0.75rem;
}
.app-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
}
.app-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.app-text {
font-size: 0.85rem;
color: var(--vp-c-text-1);
}
</style>