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;
}
使用数组实现队列结构
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();
链表
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 == null
current = 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;
}
}
集合代码实现
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); //交集
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 的值了
//并集
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}
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;
}
//获取全部键名 es6
this.keys = function(){
return Object.keys(items);
}
}
名称/键 | 散列函数 | 散列值 | 散列表 |
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 |
var HashTable = function(){
var items = [];
//散列函数1:冲突相对比较
this.loseloseHashCode = function(key){ //通过ASCII码转换生成key
var hash = 0
for (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码转换生成key
var hash = 0
for (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码转换生成key
var hash = 0
for (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;
}
}