js数据结构与算法

变量作用域

作用域指在编写的算法函数中,我们能访问的变量。有本地变量和全局变量两种。

var myVaribale = 'global';
myOtherVaribale = 'global';

function myFunction(){
    var myVaribale = 'local';
    return myVaribale;
}

function myOtherFunction(){
    myOtherVaribale = 'local';
    return myOtherVaribale;
}     

console.log(myVariable);//'global'
console.log(myFunction());//'local'

console.log(myOtherVaribale);//'global'
console.log(myOtherFunction());//'local'
console.log(myOtherVaribale);//'local'

操作符

编程语言里都需要操作符。在JS里有算数操作符、赋值操作符、比较操作符、逻辑操作符、位操作符、一元操作符和其他操作符。

//算数操作符                                                 //赋值操作符
+                            加法                           =                   赋值
-                            减法                           +=                 加/赋值(x += y) == (x = x + y)          
*                            乘法                           -=                 减/赋值(x -= y) == (x = x - y)  
/                            除法                          *=                  乘/赋值(x *= y) == (x = x * y)  
%                            取余                          /=                  除/赋值(x /= y) == (x = x / y)  
++                           递增                          %=                  取余/赋值(x %= y) == (x = x % y)  
--                           递减

//比较操作符                                                //逻辑操作符
==                           相等                             &&                   与
===                          全等                             ||                   或
!=                          不等                              !                   非
>                            大于
>=                           大等于
<                            小于
<=                           小等于

真值假值

数值类型                                         转换成布尔值
undefined                                        false
null                                                  false
布尔值                                              true--true,false ---false
数字                                                 0和NaN----false,其他都是true
字符串                                              空字符串为 false,其他都是true
对象                                                 true 
注:new 出来的为对象始终为true  (new String('') ---- true)

相等操作符

类型(x)                        类型(y)                              结果
null                                  undefined                            true
数字                                字符串                                   x == toNumber(y)
布尔值                             任何类型                               toNumber(x) == y
字符串或数字                    对象                                    x == toPrimitive(y)

面向对象

创建普通对象有两种方式:
1、var obj = new Object();
2、var obj = {};
创建完成对象:
obj = {
    name:{
          first:'Gandalf'
      }
}
在OOP中,对象是类的实例。一个类定义了对象的特征。我们会创建很多类来表示算法和数据结构。
function Book(title, pages, isbn){
    this.title = title;
    this.pages = pages;
    this.isbn = isbn;
}
实例化这个类:
var book = new Book('title','pag','isbn');
修改对象的属性:
book.title = 'new title';
原型里声明和使用函数:
Book.prototype.printTitle = function(){
    console.log(this.title);
};
直接在类的定义里声明函数:
function Book(title, pages, isbn){
    this.title = title;
    this.pages = pages;
    this.isbn = isbn;
    this.printIsbn = function(){
        console.log(this.isbn);
    }
};
在原型的例子里,printTitle方法只会创建一次,在Book类的所有实例中共享。如果在定义类的内部结构时声明,每个类的实例都会有一份该方法的副本。最好在声明公共方法时使用基于原型的方法。

数组

创建斐波那契数列,第一个数字是1,第二个是2,第三项开始,每一项等于前两项之和:
var fibonacci = [];
fibonacci[0] = 1;
fibonacci[1] = 2;
for(var i = 2; i<20;i++){
    fibonacci[i] = fibonnacci[i-1] + fibonnacci[i-2];
}
数组方法:
1、array.push:往数组末尾添加任意元素
2、array.unshift:往数组首位添加任意元素
3、array.pop:删除数组最后一位元素,并返回这个元素
4、array.shift:删除数组第一位元素,并返回这个元素
5、array.splice:往数组任意位置删除或添加任意元素  
    PS: --array.splice(1,3)--- 在数组第二位删除3项元素,并以数组形式返回被删除元           素;
      --array.splice(1,0,2,3,4)---往数组的第二位添加2,3,4三项元素,若删除元素为 0,则返回空数组;
6、array.concat:连接2个或更多数组,并返回结果;
7、array.every:对数组中的每一项运行给定函数,直到返回false,如果每一项都返回true,则返回true;
    PS:--array.every(function(x){
          return  (x % 2 == 0)
    })    --------返回true 或者 false
8、array.some:该方法和every方法类似,对数组中的每一项运行给定函数,如果任一项返回true,则返回true;
    PS:--array.some(function(x){
          return  (x % 2 == 0)
    })    --------返回true 或者 false
9、array.forEach:对数组中的每一项运行给定函数,该方法没有返回值;
10、array.map:对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组;
    PS:--var a = [1,2,3,4,5];
     a.map(function(x){
          return x +1 
    })   ----------返回数组[2,3,4,5,6],注:a数组不变;
11、array.filter:对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组;
     PS:--var a =[1,2,3,4,5];
      a.filter(function(x){
            return (x % 2 == 0);
      })   --------返回数组[2,4],a数组不变
12、array.reduce:该方法可接收一个函数作为参数和一个初始值,第一次调用函数会将初始值作为参数而非数组值,这个函数有四个参数:  previousValue、currentValue、index和array。这个函数会返回一个将被叠加到累加器的值,reduce方法停止执行后会返回这个累加器。如果要对一个数组中的所有元素求和,这就很有用;
      PS:--function process(previousArray,currentValue){
                      var nextArray;
                      if(currentValue >= 1 && currentValue <= 10){
                            nextArray = previousArray.push(currentValue);
                     }else{
                            nextArray = previousArray
                    }
                    return nextArray;
              }
              var numbers = [20,1,-4,6,30,5,8],emptyArray = [];
              numbers .reduce(process,emptyArray);--------返回数组[1,6,5,8]
13、array.reverse:反序排列数组,原先数组最后一位元素变成第一位;
14、array.sort:按照字母顺序对数组进行排列,支持传入指定排序方法的函数作为参数
       PS: ----var numbers = [2,3,5,7,1,6,8];
            numbers.sort(function(a,b){
                  return a-b
            })-----返回numbers数组[1,2,3,5,6,7,8],a-b为升序排列,b-a为降序排列;若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值,做升序排列。
15、array.indexOf:返回与参数匹配的第一个元素的索引,若参数不在数组里则返回-1;
16、array.lastIndexOf:返回与参数匹配的最后一个元素的索引。
17、array.toString:把数组里的所有元素输出为一个字符串;
       PS:---var numbers = [1,2,3,4,5];
                 numbers.toString() ----- 返回字符串'1,2,3,4,5',不改变原数组;
18、array.join:把数组里的所有元素用参数拼接;
       PS:---var numbers = [1,2,3,4,5];
                   numbers.join('-')  ---- 返回'1-2-3-4-5',不改变原数组;
推荐资源:
      1、http://www.w3schools.com/js/js_arrays.asp;
      2、http://www.w3schools.com/js/js_array_methods.asp;
      3、Mozilla的数组及其方法的页面
      4、数组库:Underscore:  http://underscorejs.org/      Lo-Dash:  http://lodash.com/

栈是一种遵从后进先出原则的有序集合。新添加的或待删除的元素都保存在栈的末尾,称作栈顶,另一端就叫栈底。在栈里,新元素都靠近栈顶,就元素都接近栈底。

栈的创建
我们创建一个类来表示栈:
function Stack(){};
首先,我们需要一种数据结构来保存栈里的元素。可以选择数组:
var items = [];
接下来,要为我们的栈声明一些方法:
1、push(element(s)):添加一个(或几个)新元素到栈顶。
2、pop():移除栈顶的元素,同时返回被移除的元素。
3、peek():返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶的元素,仅仅返回它)。
4、isEmpty():如果栈里没有任何元素就返回true,否则返回false。
5、clear():移除栈里的所有元素。
6、size():返回栈里的元素个数。这个方法和数组的length属性很类似。

首先,我们要实现的第一个方法是push。这个方法往栈里添加新元素,只添加元素到栈顶,也就是栈的末尾。
this.push = function(element){
      items.push(element);
};
因为我们使用了数组来保存栈里的元素,所以我们可以使用数组里的push方法来实现。

接着,我们实现第二个方法pop。这个方法主要用来移除栈里的元素。栈遵循后进先出的原则,因此移除的是最后添加进去的元素,所以我们可以使用数组里的pop方法来实现。 
this.pop = function(){
    return items.pop();
}
只能用push和pop方法添加和删除栈中元素,这样一来,我们的栈自然就遵从了lifo原则。

现在,为我们的类实现一些额外的辅助方法。如果想知道栈里面最后添加的元素是什么,可以用peek方法。
this.peek = function(){
    return items[items.length-1];
}

接着要实现的方法是isEmpty,如果栈为空的话就返回true,否则就返回false;
this.isEmpty = function(){
    return items.length == 0;
}

类似于数组的length属性,我们也能实现栈的长度方法size;
this.size = function(){
    return items.length;
}

最后,我们来实现clear方法,用来移除栈里所有的元素。
this.clear = function(){
    items = [];
}
这样栈就实现了,为了检查栈里的内容,我们来实现一个辅助方法,叫print,它会把栈里的元素都输出到控制台。
this.print = function(){
    console.log(items.toString());
}
这样,我们就完整创建了栈!
使用栈
现在我们就来实现一个十进制转化成二进制的过程:
function divideBy2(decNumber){
    var remStack = new Stack(),rem,binaryString = '';
    while(decNumber >0){
        rem = Math.floor(decNumber % 2);
        remStack.push(rem);
        decNumber = Math.floor(decNumber / 2)
    }
    
    while(!remStack.isEmpty()){
        binaryString += remStack.pop().toString();
    }
    
    return binaryString;
}

这样,我们修改下上面的算法,就能把十进制转换成任何进制。
function baseConverter(decNumber,base){
    var remStack = new Stack(),rem,baseString='',digits='0123456789ABCDEF';
    while(decNumber >0){
         rem = Math.floor(decNumber % base);
         remStack.push(rem);
         decNumber = Math.floor(decNumber / base);
    }

    while(!remStack.isEmpty()){
        baseString += digits[remStack.pop()];
    }
    return baseString;
}

队列

队列和栈非常类似,但是使用了不同的原则,其是遵从先进先出原则的一组有序的项。队列在尾部添加新元素,并从顶部移除元素,最新添加的元素必须排在队列的末尾。

队列的创建
我们创建一个类来表示队列:
function Queue(){};
首先,我们需要一个用于存储队列中元素的数据结构。我们可以使用数组,就像在上一章Stack类中那样使用:
var items = [];
接下来,我们声明一些队列可用的方法:
1、enqueue(element(s)):向队列尾部添加一个(或多个)新的项。
2、dequeue():移除队列的第一项,并返回被移除的元素。
3、front():返回队列中第一个元素----最先被添加,也将是最先被移除的元素,队列不做任何变动。
4、isEmpty():如果队列中不包含任何元素,返回true,否则返回false。
5、clear():移除队列里的所有算数。
6、size():返回队列包含的元素个数,与数组的length属性类似。

首先要实现的是enqueue方法,这个方法往队列里添加新元素,只添加到队列末尾:
this.enqueue = function(element){
    items.push(element);
}
接下来要实现的是dequeue方法,这个方法删除队列里的第一项:
this.dequeue = function(){
    return items.shift();
}
只有enqueue方法和dequeue方法可以添加和移除元素,这样就确保了Queue类遵从先进先出原则。

现在,为我们的类实现一些额外的辅助方法,如果想知道队列最前面的项是什么,可以用front方法:
this.front = function(){
    return items[0]
}

接着要实现isEmpty方法,如果队列为空返回true,否则就返回false。
this.isEmpty = function(){
    return items.length == 0;
}

接着是size方法,来获取队列的长度。
this.size = function(){
    return items.length;
}

最后来实现clear方法。
this.clear = function(){
    items = [];
}
这样队列就实现了,也可以像Stack类一样增加一个print方法:
this.print = function(){
    console.log(items.toString());
}
这样,我们就实现了一个队列!
优先队列

优先队列中,元素的添加和移除是基于优先级的。一个现实的例子就是医院的急诊,要实现优先队列,有两种选项:设置优先级,然后在正确的位置添加元素;或者用入列操作添加元素,然后按照优先级移除它们。

我们创建一个类来表示优先队列:
function PriorityQueue(){
   var items = [];
   //创建一个队列元素类,在接下来的添加元素方法中会使用到
   function QueueElement(element,priority){
       this.element = element;
       this.priority = priority;
   }
};

接下来我们实现enqueue方法,在队列的正确位置添加元素。
this.enqueue = function(element,priority){
    var queueElement = new QueueElement(element,priority);
    if(this.isEmpty()){//this指向该优先队列,这里直接调用判断队列是否为空的方法
        items.push(queueElement);
    }else{
          var added = false;
          for (var i; i
循环队列

循环队列的一个例子就是击鼓传花游戏,在这个游戏里,孩子们围成一个圈,把花尽快的传递给旁边的人。某一时刻花停止,这个时候花在谁手里,谁就退出圆圈结束游戏。重复这个过程,直到只剩一个孩子(胜者)。

下面,我们实现一个模拟的击鼓传花游戏:
function  hotPotato (nameList,num){
    var queue = newQueue();
    for(var i=0;i1){
        for(var i=0;i

你可能感兴趣的:(js数据结构与算法)