汇合
成一个既没有反复元素,也没有程序概念的数组。用对象{}
示意。
function Set(){ var items={}; //向汇合增加一个新的项。true,示意增加了这个值。如果汇合中曾经有这个值,就返回false,示意没有增加它。 this.add=function(value){ if(!this.has(value)){ items[value]=value; return true; } return false; } //从汇合移除一个值。 this.remove=function(value){ if(items[value]){ delete items[value]; return true; } return false; } //如果值在汇合中,返回true,否则返回false。 this.has=function(value){ return return items.hasOwnProperty(value); } //移除汇合中的所有项。 this.clear=function(){ items={}; }//返回汇合所蕴含元素的数量。与数组的length属性相似。 this.size=function(){ return Object.keys(items).length; }//返回一个蕴含汇合中所有值的数组。 this.values=function(){ return Object.keys(items); }}
并集
对于给定的两个汇合,返回一个蕴含两个汇合中所有元素的新汇合。Object.assign()
,2个都要;
并集的数学概念,汇合A
和B
的并集,示意为A∪B
,定义如下:A∪B = { x | x ∈ A∨x ∈ B }
意思是x
(元素)存在于A
中,或x
存在于B
中。
当初来实现Set
类的union
办法:
this.union = function(otherSet){ var unionSet = new Set(); var values = this.values(); for (var i=0; i<values.length; i++){ unionSet.add(values[i]); } values = otherSet.values(); for (var i=0; i<values.length; i++){ unionSet.add(values[i]); } return unionSet;};
测试一下下面的代码:
var setA = new Set();setA.add(1);setA.add(2);setA.add(3);var setB = new Set();setB.add(3);setB.add(4);setB.add(5);setB.add(6);var unionAB = setA.union(setB);console.log(unionAB.values());
输入为["1", "2", "3", "4", "5", "6"]
。留神元素3
同时存在于A
和B
中,它在后果的汇合中只呈现一次。
交加
对于给定的两个汇合,返回一个蕴含两个汇合中共有元素的新汇合。只有同时领有的。
交加的数学概念,汇合A
和B
的交加,示意为A∩B
,定义如下:A∩B = { x | x ∈ A∧x ∈ B }
意思是x
(元素)存在于A
中,且x
存在于B
中。
当初来实现Set
类的intersection
办法:
this.intersection = function(otherSet){ var intersectionSet = new Set(); //同时都蕴含的 var values = this.values(); for (var i=0; i<values.length; i++){ if (otherSet.has(values[i])){ intersectionSet.add(values[i]); } } return intersectionSet;}
差集
对于给定的两个汇合,返回一个蕴含所有存在于第一个汇合且不存在于第二个集
合的元素的新汇合。只有跟其它不雷同的。
差集的数学概念,汇合A
和B
的差集,示意为A-B
,定义如下:A-B = { x | x ∈ A ∧ x B }
意思是x
(元素)存在于A
中,且x
不存在于B
中。
当初来实现Set
类的difference
办法:
this.difference = function(otherSet){ var differenceSet = new Set();//存在A不存在B,同样数据a.length>b.length 才会有值,[1,2,3,4]-[1,2,3]=4; var values = this.values(); for (var i=0; i<values.length; i++){ if (!otherSet.has(values[i])){ differenceSet.add(values[i]); } } return differenceSet;};
子集
验证一个给定汇合是否是另一汇合的子集。判断子集中肯定都是父集中的。
子集的数学概念,汇合A
是B
的子集(或汇合B
蕴含
了A
),示意为A⊆B
,定义如下:∀x { x ∈ A → x ∈ B }
意思是汇合A
中的每一个x
(元素),也须要存在于B
中。
当初来实现Set
类的subset
办法:
this.subset = function(otherSet){ if (this.size() > otherSet.size()){ return false; } else { var values = this.values(); for (var i=0; i<values.length; i++){ if (!otherSet.has(values[i])){ return false; } } return true; }};
字典
汇合、字典和散列表能够存储不反复的值。在字典中,存储的是[键,值]
对,其中键名是用来查问特定元素的。字典也称作映射。
function Dictionary(){ var items={}; this.set=function(key,value){ items[key]=value; } this.remove=function(key){ if(this.has(key)){ delete items[key]; return true; } return false; } this.has=function(key){ return key in items; } this.get=function(key){ return this.has(key)?items[key]:undefined; } this.clear=function(){ items={}; } this.size=function(){ return Object.keys(items).length; } this.keys=function(){ return Object.keys(items); } this.values=function(){ let values=[]; for(let key in items){ if(this.has(key)){ values.push(items[key]) } } return values; } this.getItems = function() { return items; }}
散列表
HashTable
类,也叫HashMap
类,是Dictionary
类的一种散列表实
现形式。应用数组形式。
散列算法的作用是尽可能快地在数据结构中找到一个值。道如果
要在数据结构中取得一个值(应用get
办法),须要遍历整个数据结构来找到它。如果应用散列
函数,就晓得值的具体位置,因而可能疾速检索到该值。散列函数的作用是给定一个键值,而后返回值在表中的地址。
先实现一个散列函数是HashTable类的公有办法,取得将每个键值中的每个字母的ASCII值和一个数字。
let loseloseHashCode=function(key){ let hash=5381; for(let i=0;i<key.length;i++){ hase=hash*33+key.charCodeAt(i); } return hash%1013;//1013是任意的质数,让值不要那么大}
`function HashTable(){
let table=[];this.put=function(key,value){ let position=loseloseHashCode(key); table[position]=value;}this.remove=function(key){ table[loseloseHashCode(key)]=undefined;}this.get=function(key){ return table[loseloseHashCode(key)]}
}`
树
非程序数据结构——树,它对于存储须要疾速查找的数据十分有用。
一个树结构蕴含一系列存在父子关系的节点。每个节点都有一个父节点(除了顶部的第一个
节点)以及零个或多个子节点:
位于树顶部的节点叫作根节点(11)。它没有父节点。树中的每个元素都叫作节点,节点分
为外部节点和内部节点。至多有一个子节点的节点称为外部节点(7、5、9、15、13和20是外部
节点)。没有子元素的节点称为内部节点或叶节点(3、6、8、10、12、14、18和25是叶节点)。
一个节点能够有先人和后辈。一个节点(除了根节点)的先人包含父节点、祖父节点、曾祖
父节点等。一个节点的后辈包含子节点、孙子节点、曾孙节点等。例如,节点5的先人有节点7
和节点11,后辈有节点3和节点6
二叉树
二叉树中的节点最多只能有两个子节点:一个是左侧子节点,另一个是右侧子节点。这些定
义有助于咱们写出更高效的向/从树中插入、查找和删除节点的算法。二叉树在计算机科学中的
利用十分宽泛。
二叉搜寻树(BST)是二叉树的一种,然而它只容许你在左侧节点存储(比父节点)小的值,
在右侧节点存储(比父节点)大(或者等于)的值。;
let insertNode=function(node,newNode){ //小了就在右边上级有了就找下上级,左边同理 if(newNode.key<node.key){ if(node.left===null){ node.left=newNode; }else{ insertNode(node.left,newNode) } }else{ if(node.right===null){ node.right=newNode; }else{ insertNode(node.right,newNode); } }}
function BinarySearchTree(){ let Node=function(key){ this.key=key; this.left=null; this.right=null; } let root=null; this.insert=function(key){ let newNode=new Node(key); if(root===null){ root=newNode; }else{ insertNode(root,newNode); } } this.search=function(key){ } this.inOrderTraverse=function(callback){} this.preOrderTraverse=function(){} this.postOrderTraverse=function(){} this.min=function(){} this.max=function(){} this.remove=function(key){ }}
中序遍历
中序遍历是一种以上行程序拜访BST所有节点的遍历形式,也就是以从最小到最大的程序访
问所有节点。中序遍历的一种利用就是对树进行排序操作。
首先要查看以参数模式传入的节点是否为null(这就
是进行递归继续执行的判断条件——递归算法的根本条件)。
而后,递归调用雷同的函数来拜访左侧子节点。接着对这个节点进行一些操作
(callback),而后再拜访右侧子节点
this.inOrderTraverse=function(callback){ inOrderTraverse(root,callback);}
let inOrderTraverseNode=function(node,callback){ if(node!==null){ inOrderTraverseNode(node.left,callback); callback(node.key); inOrderTraverseNode(node.right,callback); }}
inOrderTraverse
办法的拜访门路:
先序遍历
先序遍历是以优先于后辈节点的程序拜访每个节点的。先序遍历的一种利用是打印一个构造
化的文档。
先序遍历和中序遍历的不同点是,先序遍历会先拜访节点自身,而后再拜访它的
左侧子节点,最初是右侧子节点。
this.preOrderTraverse=function(callback){ preOrderTraverseNode(root,callback)}
let preOrderTraverseNode=function(node,callback){ if(node!==null){ callback(node.key); preOrderTraverseNode(node.left,callback); preOrderTraverseNode(node.right,callbak); }}
preOrderTraverse
办法的拜访门路:
后序遍历
后序遍历则是先拜访节点的后辈节点,再拜访节点自身。后序遍历的一种利用是计算一个目
录和它的子目录中所有文件所占空间的大小。
后序遍历会先拜访左侧子节点,而后是右侧子节点,最初
是父节点自身
this.postOrderTraverse=function(callback){ postOrderTraverseNode(root,callback);}
let postOrderTraverseNode=function(node,callback){ if(node!==null){ postOrderTraverseNode(node.left,callback); postOrderTraverseNode(node.right,callback); callback(node.key); }}
postOrderTraverse
办法的拜访门路:
搜寻最大最小值
小的在右边,大的在左边
this.min=function(){ return minNode(root);}let minNode=function(node){ if(node){ while(node&&node.left!==null){ node=node.left; } return node.key; } return null;}
this.max=function(){ return maxNode(root);}let maxNode=function(node){ if(node){ while(node&&node.right!==null){ node=node.right; } return node.key; } return null;}
搜寻特定值
返回boolean;
this.search=function(key){ return searchNode(root,key);}let searchNode=function(node,key){ if(node===null){ return false; } if(key<node.key){ return searchNode(node.left,key); }else if(key>node.key){ return searchNode(node.right,key); }else{ return true; }}
移除一个节点
this.remove=function(key){ root=removeNode(root,key);}let removeNode=function(node,key){ if(node===null){ return null; } if(key<node.key){ node.left=removeNode(node.left,key); }else if(key>node.key){ node.right=removeNode(node.right,key); return node; }else{//键=node.key //第一种状况,一个叶节点 if(node.left===null&&node.right===null){ node=null; return node; } //第二种状况,一个只有一个子节点的节点 if(node.left==null){ node=node.right; return node; }else if(node.right===null){ node=node.left; return node; } //第三种状况,一个有2个子节点的节点 let aux=findMinNode(node.right); node.key=aux.key; node.right=removeNode(node.right,aux.key); return node; }}