Files
test-repo/docs/.vitepress/theme/components/appendix/computer-fundamentals/HashTableDemo.vue
T

435 lines
9.2 KiB
Vue
Raw Normal View History

<template>
<div class="hash-table-demo">
<div class="demo-header">
<span class="icon">🗂</span>
<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 @click="addData" class="add-btn">
添加
</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 .icon { font-size: 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>