数据结构栈

  • 后进先出(兜儿),栈应该有如下方法:

    • 入栈 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

字典(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
    Adam
    74+111+98+115
    66+111+98
    85+100+97+109
    398
    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 小笔记 - 数据结构 栈,队列,链表,字典,集合,哈希表(散列表)相关推荐

  1. 数据结构:哈希表(散列表)基础

    哈希表(散列表)基础 引入哈希表 什么是哈西表: 一种具有相同特性的数据元素的集合,每个元素具有唯一标识自己的关键字. 基本原理: 说明: 顺序查找.二分查找或者二叉树的查找是基于待查关键字与表中元素 ...

  2. 数据结构栈队列链表数组

    目录: 数据结构 栈(stack) 队列 链表 数组 数据结构 数据结构是什么 简单来说,数据结构就是设计数据以何种方式存储在计算机中 比如:列表,集合,与字典等都是一种数据结构 程序 = 数据结构 ...

  3. 算法小讲堂之哈希表|散列表|考研笔记

    文章目录 一. 基本概念 二. 哈希函数|散列函数 2.1 直接定址法 2.2 保留余数法 2.3 数字分析法 2.4 平方取中法 2.5 折叠法 2.6 随机数法 三.冲突处理 3.1 开放定址法 ...

  4. 【数据结构笔记39】哈希表/散列表、(数据关键字/字符串关键字)散列构造函数

    本次笔记内容: 11.1.1 引子:散列的基本思路 11.1.2 什么是散列表 11.2.1 数据关键词的散列函数构造 11.2.2 字符串关键词的散列函数构造 文章目录 散列表背景 基本思想引出 已 ...

  5. JavaScript数据结构与算法(2)(集合、字典、哈希表、二叉树、图)(ES6)

    注意:原教学视频:JavaScript(ES6)数据结构和算法 | JavaScript数据结构与算法 (都是CoderWhy老师的教学) 原作者(笔记)链接:JavaScript 数据结构与算法 | ...

  6. php数据结构之线性表,php数据结构之顺序链表与链式线性表示例

    本文实例讲述了php数据结构之顺序链表与链式线性表.分享给大家供大家参考,具体如下: 链表操作 1. InitList(L):初始化链表 2. DestroyList(L):删除连接 3. Clear ...

  7. Python数据结构 四种链表的集合

    python数据结构四个链表的集合 结点的创建 import os# 创建节点 class Node:def __init__(self, data):self.data = dataself.nex ...

  8. 10_JavaScript数据结构与算法(十)哈希表

    JavaScript 数据结构与算法(十)哈希表 认识哈希表 哈希表是一种非常重要的数据结构,几乎所有的编程语言都直接或者间接应用这种数据结构. 哈希表通常是基于数组实现的,但是相对于数组,它存在更多 ...

  9. 数据结构学习——线性结构结构之哈希表

    目录 一.哈希表的基本介绍 二.六种哈希函数 f(key) 的构造方法 1.直接定址法 2.数字分析法 3.平方取中法 4.折叠法 5.除留余数法 6.随机数法 除留余数示例 三.哈希查找(链表) 题 ...

  10. 【练习】2021下半年数据结构刷题笔记和总结 (三)栈 队列 链表 枚举算法

    题目来自书或者网站. 解密QQ 号--队列 回文字符串---栈 火柴棍等式 输入数字n,要求输出从1~n的全排列 [力扣]给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 ...

最新文章

  1. 常见排序算法及其java实现
  2. 数据中心业界迎来机器学习工具
  3. 在集设把优秀的设计合集,轻松追寻设计灵感
  4. oracle索引大小暴增_oracle海量数据中提升创建索引的速度
  5. 51nod 1062 序列中最大的数【打表】
  6. P4234 最小差值生成树
  7. 淘宝API-item_search - 按关键字搜索淘宝商品
  8. CC00054.bigdatajava——|Java分支结构.V04|——|Java.v04|ifelse.v02|判断负数和非负数|
  9. 视音频学习入门---ffmpeg篇(四)---基于windows平台的ffmpeg开发(二)
  10. 广西艺术学院2012年本科招生专业考试通知
  11. 让你的Onedrive网盘秒变网站,文件展示,直连下载,视频在线播放
  12. Win11找不到DNS地址怎么办?Win11找不到DNS无法访问网页解决方法
  13. linux 安装toolchain工具
  14. 公有链规模可扩展性的讨论 PPT
  15. android6.0数据恢复,安卓6.0以上提取技术和微信恢复研究.pdf
  16. 信息孤岛问题有多难?教你一招,免费解决
  17. 区块链会员积分体系解决方案
  18. Android菜鸟笔记-实现一键重启和关机
  19. zabbix安装记事:The frontend does not match Zabbix database
  20. 你好2017! 再见2015, 再见小码哥!

热门文章

  1. linux下大文件分割
  2. 腾讯对战平台显示版本服务器连接超时,腾讯对战平台怎么了_腾讯对战平台出现问题怎么解决...
  3. XSS篇——javascript:伪协议
  4. Selenium||解决给元素输入文本失败问题
  5. hp proliant DL360p Gen8风扇故障排除
  6. 论文学习——基于滑动窗口预测的水位时间序列异常检测
  7. 蔡司数码视疲劳测试软件_[专题]重度近视别担心!!蔡司数码型镜片真实测评,带给我不一样的体验...
  8. Android 清理大师产品的具体实现(一)QQ专清
  9. 白帽SEO为什么更好?
  10. Web服务器、应用服务器、数据库服务器之间的关系