下面是维基百科的解释:
数据结构是计算机存储、组织数据的方式。数据结构意味着接口或封装:一个数据结构可被视为两个函数之间的接口,或者是由数据类型联合组成的存储内容的访问方法封装。
我们每天的编码中都会用到数据结构,下面是常见的数据结构:
散列表(Hash)是一种常用的数据结构,用于存储键值对。它利用散列函数将键映射到一个数字索引上,以便快速地插入、删除和查找数据。在JavaScript 中,可以使用对象来实现散列表的功能。
用数组或链表存储数据时,若想要找到其中一个数据,需要从头进行遍历,因为不知道这个数据存储在数组的哪个位置。散列表通过散列函数将键映射为一个数字,使得数据存储在特定位置,从而提高了查找效率。
在 JavaScript 中,散列表可以基于对象进行设计。数组的长度是预先设定的,所有元素根据与该元素对应的键,保存在数组的特定位置。这里的键和对象的键是类型的概念。当使用散列表存储数组时,通过一个散列函数将键映射为一个数字,这个数字的范围是0到散列表的长度。
以下是一个使用散列表存储学生信息的案例 HTML/JS 效果,其中使用了一个自己实现的散列表,实现了基本的插入、删除和查找操作:
HTML代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Student Info</title>
</head>
<body>
<input type="text" placeholder="输入名字" id="nameInput">
<input type="text" placeholder="输入成绩" id="scoreInput">
<button onclick="addStudent()">添加学生</button>
<br><br>
<input type="text" placeholder="输入要搜索的名字" id="searchInput">
<button onclick="searchStudent()">搜索学生</button>
<br><br>
<label for="result">结果: </label>
<span id="result"></span>
<script src="hashTable.js"></script>
</body>
</html>
JavaScript代码:
// 自定义散列函数
function hashFunction(key) {
var hash = 0;
for (var i = 0; i < key.length; i++) {
hash += key.charCodeAt(i);
}
return hash % 100; // 假设散列表有 100 个位置
}
// 自定义散列表类
function HashTable() {
this.table = new Array(100); // 创建一个大小为 100 的数组作为散列表
this.add = function (key, value) {
var index = hashFunction(key);
this.table[index] = value;
};
this.remove = function (key) {
var index = hashFunction(key);
this.table[index] = undefined;
};
this.find = function (key) {
var index = hashFunction(key);
return this.table[index];
};
}
// 创建一个散列表实例用于存储学生信息
var studentHash = new HashTable();
// 根据输入添加学生信息
function addStudent() {
var name = document.getElementById("nameInput").value;
var score = document.getElementById("scoreInput").value;
studentHash.add(name, score);
console.log(studentHash.table);
}
// 根据输入查找学生的成绩
function searchStudent() {
var name = document.getElementById("searchInput").value;
var score = studentHash.find(name);
if (score !== undefined) {
document.getElementById("result").textContent = score;
} else {
document.getElementById("result").textContent = "没有找到相关数据";
}
}
上述代码中,首先定义了一个散列函数 hashFunction,该函数将输入的键通过字符编码相加并取余操作,得到散列的索引。然后创建了一个自定义的散列表类 HashTable,内部使用一个大小为 100 的数组作为散列表的存储结构。散列表的 add() 方法根据键的散列值将值存储到相应的位置上,remove() 方法按键的散列值将相应位置的值置为 undefined,find() 方法根据键的散列值查找对应的值。
在 HTML 中,通过输入框和按钮来添加学生,并通过另一个输入框和按钮来查找学生的成绩。在 JS 的实现中,添加学生和查找学生都是通过散列表的 add() 和 find() 方法实现的。当添加学生时,根据学生的姓名计算出散列值,然后将对应的成绩存储到散列表中。当查找学生时,根据输入的姓名计算出散列值,并在散列表中查找对应的成绩,最后将结果在页面上展示出来。
总体来说,上述代码实现了使用散列表存储学生信息的基本功能。
在散列表中,当两个不同的键被映射到相同的位置时,就会发生碰撞。为了解决这个问题,有两种常见的方法:开链法和线性探测法。
开链法是一种简单而直观的碰撞解决方法。它使用数组来存储散列中的每个槽位,每个槽位都是一个链表或者数组。当发生碰撞时,新的键值对会被添加到对应槽位的链表或数组上。
示例:
假设我们有一个散列表,其中包含10个槽位。当发生碰撞时,我们将键值对存储在对应槽位的链表或数组中。例如,如果键 “apple” 和 “banana” 都被映射到槽位 3,并且已经有一个键值对 “apple: red” 存储在该位置上,那么 “banana: yellow” 将会被添加到 “apple: red” 后面,形成一个链表或数组。
线性探测法是另一种处理碰撞的方法。当发生碰撞时,线性探测法会顺序地检查下一个槽位,直到找到一个空的槽位来存储新的键值对。
示例:
假设我们有一个散列表,其中包含10个槽位。当发生碰撞时,线性探测法会依次检查下一个槽位,直到找到一个空的槽位。例如,如果键 “apple” 被映射到槽位 3,但该位置已经被占用,线性探测法会继续检查槽位 4、5 直到找到一个空的槽位来存储 “apple: red”。
这两种方法提供了灵活的方式来处理散列表中的碰撞,确保即使发生碰撞,仍然能够有效地存储和检索数据。
总体来说,选择开链法还是线性探测法取决于具体应用场景和对性能、内存的不同需求。
持续学习总结记录中,回顾一下上面的内容:
散列表(Hash)是一种常用的数据结构,用于存储键值对。它利用散列函数将键映射到一个数字索引上,以便快速地插入、删除和查找数据。在JavaScript 中,可以使用对象来实现散列表的功能。