JavaScript数据结构

数组

数组实现

  1. 创建和初始化数组
var daysOfWeek=[];
daysOfWeek=['Sunday', 'Monday', 'Tuesday', 'Wednesday','Thursday', 'Friday', 'Saturday'];
  1. 访问和迭代数组
for (var i=0;i<daysOfWeek.length;i++){
    console.log(daysOfWeek[i]);
}
  1. 添加元素
//尾添加
numbers.push(12, 13);
//or
numbers[numbers.length]=10;
//首添加
numbers.unshift(-4, -3);
//or
for(var i=numbers.length;i>0;i--){
    numbers[i]=numbers[i-1];
}
numbers[0]=-1;
  1. 删除元素
//尾删除
numbers.pop();
//or
numbers.length=numbers.length-1;
//首删除
numbers.shift();
//or
for(var i=0;i<numbers.length;i++){
    numbers[i]=numbers[i+1];
}
numbers.length=numbers.length-1;
  1. 在任意位置添加和删除元素
//添加
numbers.splice(5,0,2,3,4);
//删除
numbers.splice(5,3);

JavaScript数组的其他方法

  1. 数组合并
var zero=0;
var positiveNumbers=[1,2,3];
var negativeNumbers=[-3,-2,-1];
var numbers=negativeNumbers.concat(zero, positiveNumbers);
  1. 迭代器函数
var isEven=function(item){
   return (x%2==0)?true:false;
}
//every,每一项返回true时,整体返回true
numbers.every(isEven);
//some,任意一项返回true,整体返回true
numbers.some(isEven);
//filter,整体返回由返回值为true的项组成的数组
var evenNumbers=numbers.filter(isEven);
//map,整体返回由返回值组成的数组
var myMap=numbers.map(isEven);
//reduce,整体返回叠加的值
numbers.reduce(function(previous, current, index){
   return previous + current;
});
//forEach,对数组每一项执行传入函数
numbers.forEach(function(x){
   console.log((x % 2 == 0));
});

栈(LIFO)

栈实现

function Stack(){
    let items=[];
    //向栈添加元素
    this.push=function(element){
        items.push(element);
    };
    //从栈移除元素
    this.pop=function(){
        return items.pop();
    };
    //查看栈顶元素
    this.peek=function(){
        return items[items.length-1];
    };
    //检查栈是否为空
    this.isEmpty=function(){
        return items.length==0;
    };
    this.size=function(){
        return items.length;
    };
    //清空和打印栈元素
    this.clear=function(){
        items=[];
    };
    this.print=function(){
        console.log(items.toString());
    };
}
//使用Stack类
let stack=new Stack();

ECMAScript 6 实现Stack 类

  1. ES6声明Stack类
class Stack{
    constructor(){
        this.items=[];
    }
    push(element){
        this.items.push(element);
    }
    //其他方法
}

队列(FIFO)

队列实现

function Queue(){
    let items=[];
    //向队列添加元素
    this.enqueue=function(element){
        items.push(element);
    };
    //从队列移除元素
    this.dequeue=function(){
        return items.shift();
    };
    //查看队列头元素
    this.front=function(){
        return items[0];
    };
    //检查队列是否为空
    this.isEmpty=function(){
        return items.length == 0;
    };
    this.size=function(){
        return items.length;
    };
    //打印队列元素
    this.print=function(){
        console.log(items.toString());
    };
}
//使用Queue类
let queue=new Queue();

链表

数组的缺点:

  1. 大小固定
  2. 移动数据成本高
  3. 数据存储需要连续的空间

链表的缺点:

  1. 获取数据成本高

实现单向链表

function LinkedList(){
    //节点类
    let Node=function(element){
        this.element=element;
        this.next=null;
    };
    let length=0;
    let head=null;
    this.append=function(element){
        let node=new Node(element);
        let current;
        //空链表
        if(head===null){
            head=node;
        }else{
            current=head;
            while(current.next){
                current=current.next;
            }
            current.next=node;
        }
        length++;
    };
    this.insert=function(position,element){
        //检查越界
        if(position>=0&&position<=length){
            let node=new Node(element);
            let current=head;
            let previous;
            let index=0;
            if(position===0){
                node.next=current;
                head=node;
            }else{
                while(index<position){
                    previous=current;
                    current=current.next;
                    index++;
                }
                node.next=current;
                previous.next=node;
            }
            length++;
            return true;
        }else{
            return false;
        }
    };
    this.removeAt=function(position){
        //检查越界
        if(position>=0&&position<length){
            let current=head;
            let previous;
            index=0;
            if(position===0){
                head=current.next;
            }else{
                while(index<position){
                    previous=current;
                    current=current.next;
                    index++;
                }
                previous.next=current.next;
            }
            length--;
            return current.element;
        }else{
            return null;
        }
    };
    this.indexOf=function(element){
        let current=head;
        let index=0;
        while(current){
            if(element===current.element){
                return index;
            }
            index++;
            current=current.next;
        }
        return -1;
    };
    this.remove=function(element){
        let index=this.indexOf(element);
        return this.removeAt(index);
    };
    this.toString=function(){
        let current=head;
        let string='';
        while(current){
            string+=current.element+(current.next?'n':'');
            current=current.next;
        }
        return string;
    };
    this.isEmpty=function(){
        return length===0;
    };  
    this.size=function(){
        return length;
    };
    this.getHead=function(){
        return head;
    };
}

实现双向链表

function DoublyLinkedList(){
    let Node=function(element){
        this.element=element;
        this.next=null;
        this.prev=null;
    };
    let length=0;
    let head=null;
    let tail=null;
    this.insert=function(position,element){
        //检查越界
        if(position>=0&&position<=length){
            let node=new Node(element);
            let current=head;
            let previous;
            let index=0;
            if(position===0){
                if(!head){
                    head=node;
                    tail=node;
                }else{
                    node.next=current;
                    current.prev=node;
                    head=node;
                }
            }else if(position===length){
                current=tail;
                current.next=node;
                node.prev=current;
                tail=node;
            }else{
                while(index<position){
                    previous=current;
                    current=current.next;
                    index++;
                }
                node.next=current;
                current.prev=node;
                previous.next=node;
                node.prev=previous;
            }
            length++;
            return true;
        }else{
            return false;
        }
    };
    this.removeAt=function(position){
        if(position>=0&&position<length){
            let current=head;
            let previous;
            let index=0;
            if(position===0){
                head=current.next;
                if(length===1){
                    tail=null;
                }else{
                    head.prev=null;
                }
            }else if(position===length-1){
                current=tail;
                tail=current.prev;
                tail.next=null;
            }else{
                while(index<position){
                    previous=current;
                    current=current.next;
                    index++;
                }
                previous.next=current.next;
                current.next.prev=previous;
            }
            length--;
            return current.element;
        }else{
            return null;
        }
    }
}

集合

集合是由一组无序且唯一(即不能重复)的项组成的,ECMAScript 6原生支持Set类

集合实现

function Set(){
    let items={};
    this.has=function(value){
        return value in items;
    };
    this.add=function(value){
        if(!this.has(value)){
            items[value]=value;
            return true;
        }
        return false;
    };
    this.remove=function(value){
        if(this.has(value)){
            delete items[value];
            return true;
        }
        return false;
    };
    this.clear=function(){
        items={};
    };
    this.size=function(){
        return Object.keys(items).length;
    };
    this.values=function(){
        let values=[];
        for(let i=0,keys=Object.keys(items);i<keys.length;i++){
            values.push(items[keys[i]]);
        }
        return values;
    }
}
//使用Set类
let set=new Set();

实现集合操作

  1. 并集
function Set(){
    //其他实现代码

    //Set类的union方法
    this.union=function(otherSet){
        let unionSet=new Set();
        let values=this.values();
        for(let i=0;i<values.length;i++){
            unionSet.add(values[i]);
        }
        values=otherSet.values();
        for(let i=0;i<values.length;i++){
            unionSet.add(values[i]);
        }
        return unionSet;
    }
}
  1. 交集
function Set(){
    //其他实现代码

    this.intersection=function(otherSet){
        let intersectionSet=new Set();
        let values=this.values();
        for(let i=0;i<values.length;i++){
            if(otherSet.has(values[i])){
                intersectionSet.add(values[i]);
            }
        }
        return intersectionSet;
    }
}
  1. 差集
function Set(){
    //其他实现代码

    this.difference=function(otherSet){
        let differenceSet=new Set();
        let values=this.values();
        for(i=0;i<values.length;i++){
            if(otherSet.has(values[i])){
                differenceSet.add(values[i]);
            }
        }
        return differenceSet;
    }
}
  1. 子集
function Set(){
    //其他实现代码

    this.subset=function(otherSet){
        if(this.size()>otherSet.size()){
            return false;
        }else{
            let values=this.values();
            for(let i=0;i<values.length;i++){
                if(!otherSet.has(values[i])){
                    return false;
                }
            }
            return true;
        }
    }
}

字典和散列表

字典和集合很相似,集合以[值,值]的形式存储元素,字
典则是以[键,值]的形式来存储元素。字典也称作映射,字典的键是唯一的

字典实现

function Dictionary(){
    let items={};
    this.has=function(key){
        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 this.has(key)?items[key]:undefined;
    };
    this.values=function(){
        let values=[];
        for(let key in items){
            values.push(items[key]);
        }
        return values;
    };
    this.keys=function(){
        return Object.keys(items);
    };
    this.getItems=function(){
        return items;
    };
}
//使用Dictionary 类
let dictionary=new Dictionary();

散列映射和字典一样键是唯一的,散列映射的键对应的散列值代表实际值在散列表中的地址
散列函数:键值经过散列函数得到散列值

散列表实现

function HashTable(){
    let table=[];
    //散列函数
    let loseloseHashCode=function(key){
        let hash=0;
        for(let i=0;i<key.length;i++){
            hash+=key.charCodeAt(i);
        }
        return hash%37;
    };
    this.put=function(key,value){
        let position=loseloseHashCode(key);
        console.log(position+' - '+key);
        table[position]=value;
    };
    this.get=function(key){
        return table[loseloseHashCode(key)];
    };
    this.remove=function(key){
        table[loseloseHashCode(key)]=undefined;
    };
}
//使用 HashTable 类
let hash=new HashTable();

散列集合和集合一样值是唯一的,散列的值对应的散列值代表实际值在散列表中的地址
散列函数:实际值经过散列函数得到散列值


和散列映射一样是非顺序数据结构,对于存储需要快速查找的数据非常有用

tree.jpg

  • 位于树顶部的节点叫作根节点(11)。它没有父节点。树中的每个元素都叫作节点,节点分
    为内部节点和外部节点。至少有一个子节点的节点称为内部节点(7、5、9、15、13和20是内部
    节点)。没有子元素的节点称为外部节点或叶节点(3、6、8、10、12、14、18和25是叶节点)
  • 一个节点可以有祖先和后代。一个节点(除了根节点)的祖先包括父节点、祖父节点、曾祖
    父节点等。一个节点的后代包括子节点、孙子节点、曾孙节点等。例如,节点5的祖先有节点7
    和节点11,后代有节点3和节点6
  • 有关树的另一个术语是子树。子树由节点和它的后代构成。例如,节点13、12和14构成了上
    图中树的一棵子树
  • 节点的一个属性是深度,节点的深度取决于它的祖先节点的数量。比如,节点3有3个祖先节
    点(5、7和11),它的深度为3
  • 树的高度取决于所有节点深度的最大值。一棵树也可以被分解成层级。根节点在第0层,它
    的子节点在第1层,以此类推。上图中的树的高度为3(最大高度已在图中表示——第3层)

二叉树和二叉搜索树
二叉树中的节点最多只能有两个子节点:一个是左侧子节点,另一个是右侧子节点。
二叉搜索树(BST)是二叉树的一种,但是它只允许你在左侧节点存储(比父节点)小的值,
在右侧节点存储(比父节点)大(或者等于)的值

实现二叉搜索树

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);
        }
    };
    //插入节点辅助函数
    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);
            }
        }
    };
    //树的遍历-中序遍历
    this.inOrderTraverse=function(callback){
        inOrderTraverseNode(root,callback);
    };
    let inOrderTraverseNode=function(node,callback){
        if(node!==null){
            inOrderTraverseNode(node.left,callback);
            callback(node.key);
            inOrderTraverseNode(node.right,callback);
        }
    };
    //树的遍历-先序遍历
    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,callback);
        }
    };
    //树的遍历-后序遍历
    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);
        }
    };
    //搜索树中的值
    //搜索最小值
    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;
    };
    //搜索特定值
    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);
            return node;
        }else if(key>node.key){
            node.right=removeNode(node.right,key);
            return node;
        }else{
            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.right;
                return node;
            }
            let aux=findMinNode(node.right);
            node.key=aux.key;
            node.right=removeNode(node.right,aux.key);
            return node;
        }
    };
    let findMinNode=function(node){
        while(node&&node.left!==null){
            node=node.left;
        }
        return node;
    };
    
}
let tree=new BinarySearchTree();
function printNode(value){
    console.log(value);
}
//调用中序遍历
tree.inOrderTraverse(printNode);
//调用先序遍历
tree.preOrderTraverse(printNode);
//调用后序遍历
tree.postOrderTraverse(printNode);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容