Tracy JS 小笔记 - 数据结构 栈,队列,链表,字典,集合,哈希表(散列表)
数据结构栈
- 后进先出(兜儿),栈应该有如下方法:
- 入栈 push() 添加栈顶元素
- 出栈 pop() 移除栈顶元素
- 获取栈顶元素 peek()
- 是否为空 isEmpty()
- 清空栈 clear()
- 栈元素个数 size()
js 实现栈结构 -- 封装数组 var Stack = function(){var items = []; //这个变量需要是一个私有的,外部看不到的,这样才是一个栈,不要写成 this.item = []; 否则容易被别人串改this.push = function(ele){items.push(ele);}this.pop = function(){return items.pop();}this.peek = function(){return items[items.length - 1];}this.isEmpty = function(){return items.length == 0;}this.clear = function(){items = [];}this.size = function(){return items.length;} }var s = new Stack(); s.push("0");10 进制转换成 n 进制, 用的是余数法:function tenToN(number, n){var yushu;var s = new Stack(); //我们用的是栈的思想,先进后出var resault = "";while(number > 0){yushu = number % n;s.push(yushu);number = Math.floor(number / n);}while(!s.isEmpty()){resault += s.pop();}return resault; }
- 栈作用: 在编程语言的编译器和内存中保存变量、方法调用
- 函数调用的时候,是在内存栈里入栈
函数真正执行的时候,是在内存栈里出栈
(Tips: 所以说递归如果没有出口,是不停入栈而不出栈,会导致栈溢出)
队列
- 先进先出,队列应该有如下方法
- 入列 enqueue()
- 出列 dequeue()
- 查看列头 front()
使用数组实现队列结构 function Queue(){var items = [];this.enqueue = function(ele){items.push(ele);}this.dequeue = function(){return items.shift();}this.front = function(){return items[0];}this.isEmpty = function(){return items.length == 0;}this.clear = function(){items = [];}this.size = function(){return items.length;}this.getItem = function(){return items;} }//击鼓传花游戏,花每传三次,花在谁手上就把谁踢出去 function flowerTurn(items, number){var q = new Queue();for(var item in items){q.enqueue(items[item]);}while(q.size() > 1){for (var i = 1; i < number - 1; i ++){q.enqueue(q.dequeue()); //相当于要一个无线循环队列,当 队列头 出列后 直接入列 到队尾}console.log("淘汰的玩家是:" + q.dequeue());}console.log("最后的胜利者是:" + q.dequeue()); }//参与人员 var names = ["a", "b", "c", "d", "e", "f"]; //游戏规则 var number = 3;flowerTurn(names, number);
- 队列的应用: 下载文件, 上传文件,打印文件
- 优先队列
//飞机 高级会员 优先登机 //优先级 //小明 3 //小黑 5 function PriorityQueue(){var items = [];//辅助类var QueueItem = function(element, priority){this.element = element;this.priority = priority;}//只有入列不一样,其他方法和正常队列都是一样的this.enqueue = function(element, priority){var queueItem = new QueueItem(element, priority);//比较优先级var added = false;for (var i = 0; i < items.length; i++){if(priority > items[i].priority) {//新加入的成员优先级比当前 item 优先级高,则插入到当前元素的前面去items.splice(i, 0, queueItem);//数组方法 splice(被切割的元素位置,切割掉多少个元素,想要添加的元素...)added = true; //插入成功break;}}if(!added){items.push(queueItem);} //没有插入成功证明优先级最低,直接入列到队尾}this.getItems = function(){console.log(items);} }var p = new PriorityQueue(); p.enqueue("小明",1); p.enqueue("小黑",5); p.enqueue("小蓝",3); p.getItems();
链表
- 每个元素都有下个元素的位置
火车 : 每一列(note) 不仅要携带自己的乘客(item),还要与下一节火车相连(next)。
链表包括以下属性和方法- 链表头 head
- 链表尾 (链表尾的标志是 current.next == null;)
- node 链表元素
- element (自己的属性)
- next (链接下一个节点)
- append() 链表尾部添加元素
- insert() 链表某个位置插入元素
- removeAt() 移除链表中任意位置元素
- indexof() 获取元素第一次出现的位置
- isEmpty(); size();
自行实现: 双向链表(链表的每一个元素既链接下一个元素又链接上一个元素,因此链表头的 previous = null, 链表尾的 next = null;), 双向循环链表(最后一个链表的 next 指向链表头, 链表头的 previous 指向链表尾。 如:轮播图)
链表 var LinkList = function(){//链表头 var head = null;//链表长度, 由于链表不是数组实现的,所以要自己记录长度var length = 0;//链表元素类var Node = function(element){this.element = element;this.next = null;}//链表尾部添加元素this.append = function(element){ var node = new Node(element);if(head == null){ //当链表中没有元素的时候head = node; }else{ //当链表中有元素的时候var current = head;while(current.next){ //遍历链表到尾部 既:current.next == nullcurrent = current.next;}current.next = node; //while 循环完毕后,把元素添加到链表尾部}length ++;}this.getHead = function(){ return head;}//链表某个位置插入元素this.insert = function(position, element){ if (position == 0){//在表头添加var node = new Node(element);var current = head;head = node;head.next = current;length ++;}else if (position > -1 && position < length){ //越界问题var node = new Node(element);//在链表中插入元素var index = 0;var current = head;var previous = null; //上一个元素while (index < position){previous = current;current = current.next;index ++;}previous.next = node;node.next = current;length ++;}}//移除链表中任意位置元素this.removeAt = function(position){ if(position > -1 && position < length) {//判断越界if(position == 0){ //移除表头head = head.next;}else{var current = head;var index = 0;var previous = null;while (index < position){previous = current;current = current.next;index ++;}previous.next = current.next;}length --;}} //获取元素第一次出现的位置, 这里我们就对String 类型的 indexof 的方法有了更深了理解this.indexof = function(element){var current = head;var index = 0;while(current){if(element === current.element) {return index;}index ++;current = current.next;}return -1;}this.remove = function(element){var index = this.indexof(element);while(index != -1){this.removeAt(index);index = this.indexof(element);}}this.isEmpty = function(){return length == 0;}this.size = function(){return length;} }
集合 Set
- 集合是一个数学概念 如 A = {1,2,3}
它很像 js 里的对象 - 集合的特点
- 无重复性, 集合不能有重合的元素
- 空集
- 子集
- 集合方法
- has(value); 是否存在
- remove(value);
- add(value);
- 集合间操作
- union 并集
- intersection 交集
- difference 差集 : A 中要排除 B 的元素
集合代码实现 var Set2 = function(){var items = {};this.has = function(value){return items.hasOwnProperty(value);}this.remove = function(value){if(this.has(value)){delete items[value];return true;}return false;}this.add = function(value){if(!this.has(value)){items[value] = value;return value;}return false;}this.getItems = function(){return items;}this.clear = function(){items = {};}this.size = function(){//兼容性好的传统方法var length = 0;for(var item in items) { //for in 循环,专门遍历对象属性的if (items.hasOwnProperty(item)){length ++;} //过滤继承的属性,值遍历自己的属性 }return length; //这个是 es6 的方法,除了 IE 老版本外,都能兼容//return Object.keys(items).length;}//得到集合里的值并以数组形式返回this.value = function(){var arr = [];for(var item in items) { //for in 循环,专门遍历对象属性的if (items.hasOwnProperty(item)){arr.push(item);}}return arr;}//并集this.union = function(otherSet){var resultSet = new Set2();//1.把自己的值提取出来var arr = this.value();for(var i = 0; i < arr.length; i++){resultSet.add(arr[i]);}//2.把传来过的值提取出来arr = otherSet.value();for(var i = 0; i < arr.length; i++){resultSet.add(arr[i]);}return resultSet;}//交集this.intersection = function(otherSet){var resultSet = new Set2();//1.把自己的值提取出来,然后判断 B 里是否有这个元素var arr = this.value();for(var i = 0; i < arr.length; i++){if (otherSet.has(arr[i])) resultSet.add(arr[i]);}return resultSet;}//差集this.different = function(otherSet){var resultSet = new Set2();//1.把自己的值提取出来,然后判断 B 里是否有这个元素var arr = this.value();for(var i = 0; i < arr.length; i++){if (!otherSet.has(arr[i])) resultSet.add(arr[i]);}return resultSet;} } //由于集合是不能重复的,所以我们用对象来实现 value 和 key 相等,键值相等来实现var a = new Set2(); a.add(1); a.add(2); var b = new Set2(); b.add(2); b.add(3); var c = a.union(b); //交集
- 为何我们的集合用 Set2 而不用 Set 呢?
因为 es6 给我们提供了以下两种内置数据结构 : Set 集合; WeakSet 弱集合
Set 和 WeakSet 最大区别 : 强引用和弱引用var obj = {name: "Tracy"}; var s = new Set(); s.add(obj); obj = null; //此时 s 里仍然保留了 obj 的值, s 会一直指向 obj var obj2 = {name: "Tracy"}; var ws = new WeakSet(); ws.add(obj2); obj2 = null; //此时 ws 里就已经找不到 obj2 的值了
- Set 集合的方法
- new Set([1,2,3]); 创建对象的时候可以直接初始化元素
- add
- clear
- delete
- forEach 遍历方法
var s = new Set(); s.add(1);
s.forEach(function(key,value, set){}); - entire 获得迭代器
var interator = s.entire(); interator.next().value;
interator.next().value;
每次调用都不断返回下一项 - has
- size
- value() 获取全部值
es6 实现并交差集
//并集var a = new Set([1, 2, 3]); var b = new Set([4, 3, 2]); var union = new Set([...a, ...b]); // {1, 2, 3, 4}//交集var a = new Set([1, 2, 3]); var b = new Set([4, 3, 2]); var intersect = new Set([...a].filter(x => b.has(x))); // {2, 3} var intersect = new Set([...a].filter(function(x){return b.has(x); // filter 也是es6 里针对数组的一个方法,结果为 true 的时候 数组的值会被保留 }); // 差集var a = new Set([1, 2, 3]); var b = new Set([4, 3, 2]); var difference = new Set([...a].filter(x => !b.has(x))); // {1}
- WeakSet 集合的方法
- add, 注意这里传的参数必须是对象, 因此 s.add(1); 会报错, 必须是 s.add({"name":"Tracy"});
- delete
- has
- Set 集合的方法
字典(Dictionary)
- 字典是一种类似集合的数据结构,只不过集合是键值相等而已(key = value)
Set{1:1, 2: 2}
Dictionary{"name": "Tracy", "age" : 16}
字典的 key 不能重复,value 可以相同 - 字典的方法
- 添加键值对 set(key, value)
- 通过键值移除元素 delete(key)
- 检查键 has(key)
- 由键获取值 get(key)
var Dictionary = function(){var items = {};this.has = function(key){return items.hasOwnProperty(key);//方法 2 return key in items;}this.set = function(key, value){items[key] = value;}this.delete = function(key){if (this.has(key)) {delete items[key];return true;}return false;}this.get = function(key){return items[key];}this.getItems = function(){return items;} //获取全部键名 es6this.keys = function(){return Object.keys(items);} }
散列表(哈希表 HashTable) 和 散列算法
名称/键 散列函数 散列值 散列表 Jobs
Bob
Adam74+111+98+115
66+111+98
85+100+97+109398
275
371[275] bob@qq.com
[...]
[371] Adma@163.com
[...]
[398] jobs@qq.com- 散列表和其他数据结构
其他数据结构: 获取值的时候需要遍历元素
散列表: 可以快速定位元素,效率高
我的个人理解,哈希表就是把一个原来对象的存储,标变成了一个数组的存储。
对象在调用或者删除的时候需要从头遍历一遍
[{name : "tracy", email : "tracy@qq.com"}, {name : "bob", email : "bob1@qq.com"}]
而变成了数组,就是将 name 通过一定方式转换成数字,变成了数组的 key,然后 email 变成了数组的
value var items = [,,...,"tracy@qq.com",...,"bob1@qq.com"]; - 散列表方法
- 添加 put
- 删除
- 索引
var HashTable = function(){var items = []; //散列函数1:冲突相对比较this.loseloseHashCode = function(key){ //通过ASCII码转换生成keyvar hash = 0for (var i = 0; i< key.length; i++) {hash += key[i].charCodeAt(); //计算key的ASCII码}return hash%37; //loseloseHashCode方法计算关键码的公式,即 ASCII码取余37 }//更好的散列函数2,就不用分离链接和线性探查法了,它就是从根源上解决了原先算法的重复的问题 var djb2HashCode = function(key) {var hash = 5831;for(var i = 0; i < key.length; i++) {hash = hash * 33 + key.charCodeAt(i);}return hash % 1013;}// 新增元素 this.put = function(key,value){var position = this.loseloseHashCode(key); // 元素在散列表里的地址items[position] = value;}//移除元素this.remove = function(key){items[this.loseloseHashCode(key)] = undefined;}//获取元素this.get = function(key){return items[this.loseloseHashCode(key)];}this.getItems = function(){return items;} } var ht = new HashTable(); ht.put("tracy", "123@qq.com"); ht.put("bob", "bob@qq.com"); ht.getItems();//上面散列函数有一个缺陷,也就是计算出来的关键码 hash 有可能会相同,以至于在存储过程中会产生冲突。下面介绍两个改善的方法,可以更好的避免此类问题的发生。
分离链接法
//分离链接法,当两个名字的值的 assic code 相等的时候,会被覆盖,那么我们就在值相等的时候,存储到一个链表里 //它的缺点就是牺牲了快速定位,回到了线性查找来遍历数据 var HashTable_L = function(){var table = []; //散列函数1:冲突相对比较this.loseloseHashCode = function(key){ //通过ASCII码转换生成keyvar hash = 0for (var i = 0; i< key.length; i++) {hash += key[i].charCodeAt(); //计算key的ASCII码}return hash%37; //loseloseHashCode方法计算关键码的公式,即 ASCII码取余37 }var Node = function(key, value){this.key = key;this.value = value;}// 新增元素 this.put = function(key,value){var position = this.loseloseHashCode(key); // 元素在散列表里的地址var node = new Node(key,value);if(!table[position]){var l = new LinkList(); //链表的结构之前写过, 没有值新建链表table[position] = l;}table[position].append(node); }//移除元素this.remove = function(key){var position = this.loseloseHashCode(key);if(table[position]){//链表线性查找var current = table[position].getHead();while(current){if (current.element.key == key){table[position].remove(current.element);//如果我们删除了之后这个链表没有东西了,那么我们就释放链表 变成 undefined 来优化程序;if (table[position].isEmpty()) {table[position] = undefined;}return true;}current = current.next;}}return false;}//获取元素this.get = function(key){var position = this.loseloseHashCode(key);if(table[position]){//链表线性查找var current = table[position].getHead();while(current){if (current.element.key == key){return current.element.value;}current = current.next;}}return undefined;}this.getTable = function(){return table;} } var ht2 = new HashTable_L(); ht2.put("Ana", "Ana@qq.com"); ht2.put("Donnie", "Donnie@qq.com"); ht2.getTable()[13].getHead(); ht2.get("Ana");
线性探查法
var HashTable_X = function(){var table = []; //散列函数1:冲突相对比较this.loseloseHashCode = function(key){ //通过ASCII码转换生成keyvar hash = 0for (var i = 0; i< key.length; i++) {hash += key[i].charCodeAt(); //计算key的ASCII码}return hash%37; //loseloseHashCode方法计算关键码的公式,即 ASCII码取余37 }var Node = function(key, value){this.key = key;this.value = value;}// 新增元素,这回不创建列表了,而是看到位置被占了就往下找其他空位, 如我的座位号是13,我发现有人了,我就继续去14,15 查找 this.put = function(key,value){var position = this.loseloseHashCode(key); // 元素在散列表里的地址if(table[position] == undefined){table[position] = new Node(key,value);}else{ //这个位置被占据了var index = position + 1;while(table[index] != undefined){index++;}table[index] = new Node(key,value);}}//移除元素this.remove = function(key){var position = this.loseloseHashCode(key);if(table[position]){}return false;}//获取元素this.get = function(key){var position = this.loseloseHashCode(key);if(table[position]){}return undefined;}}
Tracy JS 小笔记 - 数据结构 栈,队列,链表,字典,集合,哈希表(散列表)相关推荐
- 数据结构:哈希表(散列表)基础
哈希表(散列表)基础 引入哈希表 什么是哈西表: 一种具有相同特性的数据元素的集合,每个元素具有唯一标识自己的关键字. 基本原理: 说明: 顺序查找.二分查找或者二叉树的查找是基于待查关键字与表中元素 ...
- 数据结构栈队列链表数组
目录: 数据结构 栈(stack) 队列 链表 数组 数据结构 数据结构是什么 简单来说,数据结构就是设计数据以何种方式存储在计算机中 比如:列表,集合,与字典等都是一种数据结构 程序 = 数据结构 ...
- 算法小讲堂之哈希表|散列表|考研笔记
文章目录 一. 基本概念 二. 哈希函数|散列函数 2.1 直接定址法 2.2 保留余数法 2.3 数字分析法 2.4 平方取中法 2.5 折叠法 2.6 随机数法 三.冲突处理 3.1 开放定址法 ...
- 【数据结构笔记39】哈希表/散列表、(数据关键字/字符串关键字)散列构造函数
本次笔记内容: 11.1.1 引子:散列的基本思路 11.1.2 什么是散列表 11.2.1 数据关键词的散列函数构造 11.2.2 字符串关键词的散列函数构造 文章目录 散列表背景 基本思想引出 已 ...
- JavaScript数据结构与算法(2)(集合、字典、哈希表、二叉树、图)(ES6)
注意:原教学视频:JavaScript(ES6)数据结构和算法 | JavaScript数据结构与算法 (都是CoderWhy老师的教学) 原作者(笔记)链接:JavaScript 数据结构与算法 | ...
- php数据结构之线性表,php数据结构之顺序链表与链式线性表示例
本文实例讲述了php数据结构之顺序链表与链式线性表.分享给大家供大家参考,具体如下: 链表操作 1. InitList(L):初始化链表 2. DestroyList(L):删除连接 3. Clear ...
- Python数据结构 四种链表的集合
python数据结构四个链表的集合 结点的创建 import os# 创建节点 class Node:def __init__(self, data):self.data = dataself.nex ...
- 10_JavaScript数据结构与算法(十)哈希表
JavaScript 数据结构与算法(十)哈希表 认识哈希表 哈希表是一种非常重要的数据结构,几乎所有的编程语言都直接或者间接应用这种数据结构. 哈希表通常是基于数组实现的,但是相对于数组,它存在更多 ...
- 数据结构学习——线性结构结构之哈希表
目录 一.哈希表的基本介绍 二.六种哈希函数 f(key) 的构造方法 1.直接定址法 2.数字分析法 3.平方取中法 4.折叠法 5.除留余数法 6.随机数法 除留余数示例 三.哈希查找(链表) 题 ...
- 【练习】2021下半年数据结构刷题笔记和总结 (三)栈 队列 链表 枚举算法
题目来自书或者网站. 解密QQ 号--队列 回文字符串---栈 火柴棍等式 输入数字n,要求输出从1~n的全排列 [力扣]给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 ...
最新文章
- 常见排序算法及其java实现
- 数据中心业界迎来机器学习工具
- 在集设把优秀的设计合集,轻松追寻设计灵感
- oracle索引大小暴增_oracle海量数据中提升创建索引的速度
- 51nod 1062 序列中最大的数【打表】
- P4234 最小差值生成树
- 淘宝API-item_search - 按关键字搜索淘宝商品
- CC00054.bigdatajava——|Java分支结构.V04|——|Java.v04|ifelse.v02|判断负数和非负数|
- 视音频学习入门---ffmpeg篇(四)---基于windows平台的ffmpeg开发(二)
- 广西艺术学院2012年本科招生专业考试通知
- 让你的Onedrive网盘秒变网站,文件展示,直连下载,视频在线播放
- Win11找不到DNS地址怎么办?Win11找不到DNS无法访问网页解决方法
- linux 安装toolchain工具
- 公有链规模可扩展性的讨论 PPT
- android6.0数据恢复,安卓6.0以上提取技术和微信恢复研究.pdf
- 信息孤岛问题有多难?教你一招,免费解决
- 区块链会员积分体系解决方案
- Android菜鸟笔记-实现一键重启和关机
- zabbix安装记事:The frontend does not match Zabbix database
- 你好2017! 再见2015, 再见小码哥!
热门文章
- linux下大文件分割
- 腾讯对战平台显示版本服务器连接超时,腾讯对战平台怎么了_腾讯对战平台出现问题怎么解决...
- XSS篇——javascript:伪协议
- Selenium||解决给元素输入文本失败问题
- hp proliant DL360p Gen8风扇故障排除
- 论文学习——基于滑动窗口预测的水位时间序列异常检测
- 蔡司数码视疲劳测试软件_[专题]重度近视别担心!!蔡司数码型镜片真实测评,带给我不一样的体验...
- Android 清理大师产品的具体实现(一)QQ专清
- 白帽SEO为什么更好?
- Web服务器、应用服务器、数据库服务器之间的关系