Javascript的數(shù)據(jù)結(jié)構(gòu)與算法

1數(shù)組 1.1方法列表 數(shù)組的常用方法如下: concat: 鏈接兩個或者更多數(shù)據(jù)结缚,并返回結(jié)果步藕。 every: 對數(shù)組中的每一項運行給定的函數(shù)蛾茉,如果該函數(shù)對每一項都返回true被廓,則返回true。 filter: 對數(shù)
1數(shù)組
1.1方法列表
數(shù)組的常用方法如下:

concat: 鏈接兩個或者更多數(shù)據(jù),并返回結(jié)果惭等。
every: 對數(shù)組中的每一項運行給定的函數(shù)褒纲,如果該函數(shù)對每一項都返回true,則返回true类溢。
filter: 對數(shù)組中的每一項運行給定函數(shù)凌蔬,返回改函數(shù)會返回true的項組成的數(shù)組。
forEach: 對數(shù)組中的每一項運行給定函數(shù)闯冷,這個方法沒有返回值砂心。
join: 將所有的數(shù)組元素鏈接成一個字符串。
indexOf: 返回第一個與給定參數(shù)相等的數(shù)組元素的索引蛇耀,沒有找到則返回-1辩诞。
lastIndexOf: 返回在數(shù)組中搜索到的與給定參數(shù)相等的元素的索引里最大的值。
map: 對數(shù)組中的每一項運行給定函數(shù)纺涤,返回每次函數(shù)調(diào)用的結(jié)果組成的數(shù)組译暂。
reverse: 顛倒數(shù)組中元素的順序,原先第一個元素現(xiàn)在變成最后一個撩炊,同樣原先的最后一個元素變成現(xiàn)在的第一個外永。
slice: 傳入索引值,將數(shù)組中對應(yīng)索引范圍內(nèi)的元素作為新元素返回衰抑。
some: 對數(shù)組中的每一項運行給定函數(shù)象迎,如果任一項返回true,則返回true呛踊。
sort: 按照字母順序?qū)?shù)組排序砾淌,支持傳入指定排序方法的函數(shù)作為參數(shù)。
toString: 將數(shù)組作為字符串返回谭网。
valueOf: 和toString相似汪厨,將數(shù)組作為字符串返回。
1.2數(shù)組合并
concat方法可以向一個數(shù)組傳遞數(shù)組愉择、對象或是元素劫乱。數(shù)組會按照該方法傳入的參數(shù)順序 連接指定數(shù)組织中。

var zero = 0;
var positiveNumbers = [1,2,3];
var negativeNumbers = [-1,-2,-3];
var numbers = negativeNumbers.concat(zero,positiveNumbers);
console.log(numbers);//輸出結(jié)果: [-1, -2, -3, 0, 1, 2, 3]

1.3迭代器函數(shù)
reduce方法接收一個函數(shù)作為參數(shù),這個函數(shù)有四個參數(shù):previousValue、currentValue衷戈、index和array狭吼。這個函數(shù)會返回一個將被疊加到累加器的 值,reduce方法停止執(zhí)行后會返回這個累加器。如果要對一個數(shù)組中的所有元素求和,這就很有用了殖妇。

var isEven = function(x){
  return (x%2 == 0)?true:false;
}
var numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
//every方法會迭代數(shù)組中的每個元素,直到返回false刁笙。
var result = numbers.every(isEven);
console.log(result);//false
//some方法會迭代數(shù)組的每個元 素,直到函數(shù)返回true.
result = numbers.some(isEven);
console.log(result);//true
//forEach對每一項運行給定的函數(shù),沒有返回值
numbers.forEach(function(item,index){
  console.log(item%2 == 0);
});
//map會迭代數(shù)組中的每個值谦趣,并且返回迭代結(jié)果
var myMap = numbers.map(isEven);
console.log(myMap);// [false, true, false, true, false, true, false, true, false, true, false, true, false, true, false]
//filter方法返回的新數(shù)組由使函數(shù)返回true的元素組成
var myFilter = numbers.filter(isEven);
console.log(myFilter);// [2, 4, 6, 8, 10, 12, 14]
//reduct函數(shù)
var myReduce = numbers.reduce(function(previous,current,index){
  return previous + "" + current;
});
console.log(myReduce);//123456789101112131415

1.4排序
var numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
numbers.reverse();//[15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
function compare(a,b){
if(a > b){
return 1;
}
if(a < b){
return -1;
}
return 0;
}
//sort函數(shù)使用
[1, 10, 11, 12, 13, 14, 15, 2, 3, 4, 5, 6, 7, 8, 9].sort(compare);

var friends = [{
  name:'huang',
  age:30
},{
  name:'chengdu',
  age:27
},{
  name:'du',
  age:31
}];
function comparePerson(a,b){
  if(a.age > b.age){
    return 1;
  }
  if(a.age < b.age){
    return -1;
  }
  return 0;
}
console.log(friends.sort(comparePerson));// [Object { name="chengdu",  age=27}, Object { name="huang",  age=30}, Object { name="du",  age=31}]
//搜索
numbers.push(10);
console.log(numbers.indexOf(10));//5
console.log(numbers.lastIndexOf(10));//15
var numbersString = numbers.join('-');
console.log(numbersString);//15-14-13-12-11-10-9-8-7-6-5-4-3-2-1-10

2棧
2.1棧的創(chuàng)建
對于一個棧疲吸,我們需要實現(xiàn)添加、刪除元素前鹅、獲取棧頂元素摘悴、已經(jīng)是否為空,棧的長度舰绘、清除元素等幾個基本操作蹂喻。下面是基本定義。

function Stack(){
  this.items = [];
}
Stack.prototype = {
  constructor:Stack,
  push:function(element){
    this.items.push(element);
  },
  pop:function(){
    return this.items.pop();
  },
  peek:function(){
    return this.items[this.items.length - 1];
  },
  isEmpty:function(){
    return this.items.length == 0;
  },
  clear:function(){
    this.items = [];
  },
  size:function(){
    return this.items.length;
  },
  print:function(){
    console.log(this.items.toString());
  }
}

2.2棧的基本使用
棧的基本操作捂寿。

var stack = new Stack();
console.log(stack.isEmpty());//true
stack.push(5);
stack.push(8);
console.log(stack.peek());//8
stack.push(11);
console.log(stack.size());//3
console.log(stack.isEmpty());
stack.push(15);
stack.pop();
stack.pop();
console.log(stack.size());//2
console.log(stack.print());//5,8

通過棧實現(xiàn)對正整數(shù)的二進制轉(zhuǎn)換叉橱。

function divideBy2(decNumber){
  var decStack = new Stack();
  var rem;
  var decString = '';
  while(decNumber > 0){
    rem = decNumber%2;
    decStack.push(rem);
    decNumber = Math.floor(decNumber/2);
  }
  while(!decStack.isEmpty()){
    decString += decStack.pop().toString();
  }
  return decString;
}
console.log(divideBy2(10));//1010

3隊列
3.1隊列的創(chuàng)建
隊列是遵循FIFO(First In First Out,先進先出,也稱為先來先服務(wù))原則的一組有序的項。隊列在尾部添加新元素,并從頂部移除元素者蠕。最新添加的元素必須排在隊列的末尾窃祝。隊列要實現(xiàn)的操作基本和棧一樣,只不過棧是FILO(先進后出)踱侣。

function Queue(){
  this.items = [];
}
Queue.prototype = {
  constructor:Queue,
  enqueue:function(elements){
    this.items.push(elements);
  },
  dequeue:function(){
    return this.items.shift();
  },
  front:function(){
    return this.items[0];
  },
  isEmpty:function(){
    return this.items.length == 0;
  },
  size:function(){
    return this.items.length;
  },
  clear:function(){
    this.items = [];
  },
  print:function(){
    console.log(this.items.toString());
  }
}

隊列的基本使用

var queue = new Queue();
console.log(queue.isEmpty());//true
queue.enqueue('huang');
queue.enqueue('cheng');
console.log(queue.print());//huang,cheng
console.log(queue.size());//2
console.log(queue.isEmpty());//false
queue.enqueue('du');
console.log(queue.dequeue());//huang
console.log(queue.print());//cheng,du

3.2 優(yōu)先隊列
元素的添加和移除是基于優(yōu)先級的粪小。實現(xiàn)一個優(yōu)先隊列,有兩種選項:設(shè)置優(yōu)先級,然后在正確的位置添加元素;或者用入列操 作添加元素,然后按照優(yōu)先級移除它們。 我們在這里實現(xiàn)的優(yōu)先隊列稱為最小優(yōu)先隊列,因為優(yōu)先級的值較小的元素被放置在隊列最 前面(1代表更高的優(yōu)先級)抡句。最大優(yōu)先隊列則與之相反,把優(yōu)先級的值較大的元素放置在隊列最 前面探膊。

3.2.1 優(yōu)先隊列的定義
我們在這里使用組合繼承的方式繼承自Queue隊列。

function PriorityQueue(){
  Queue.call(this);
};
PriorityQueue.prototype = new Queue();
PriorityQueue.prototype.constructer = PriorityQueue;
PriorityQueue.prototype.enqueue = function(element,priority){
  function QueueElement(tempelement,temppriority){
    this.element = tempelement;
    this.priority = temppriority;
  }
  var queueElement = new QueueElement(element,priority);
  if(this.isEmpty()){
    this.items.push(queueElement);
  }else{
    var added = false;
    for(var i = 0; i < this.items.length;i++){
      if(this.items[i].priority > queueElement.priority){
        this.items.splice(i,0,queueElement);
        added = true;
        break;
      }
    }
    if(!added){
        this.items.push(queueElement);
    }
  }
  
}
//這個方法可以用Queue的默認(rèn)實現(xiàn)
PriorityQueue.prototype.print = function(){
  var result ='';
  for(var i = 0; i < this.items.length;i++){
    result += JSON.stringify(this.items[i]);
  }
  return result;
}

3.2.1 優(yōu)先隊列的基本使用
var priorityQueue = new PriorityQueue();
priorityQueue.enqueue("cheng", 2);
priorityQueue.enqueue("du", 3);
priorityQueue.enqueue("huang", 1);
console.log(priorityQueue.print());//{"element":"huang","priority":1}{"element":"cheng","priority":2}{"element":"du","priority":3}
console.log(priorityQueue.size());//3
console.log(priorityQueue.dequeue());//{ element="huang", priority=1}
console.log(priorityQueue.size());//2
3鏈表
數(shù)組的大小是固定的,從數(shù)組的起點或中間插入 或移除項的成本很高,因為需要移動元素(盡管我們已經(jīng)學(xué)過的JavaScript的Array類方法可以幫 我們做這些事,但背后的情況同樣是這樣)待榔。鏈表存儲有序的元素集合,但不同于數(shù)組,鏈表中的元素在內(nèi)存中并不是連續(xù)放置的逞壁。每個 元素由一個存儲元素本身的節(jié)點和一個指向下一個元素的引用(也稱指針或鏈接)組成。

相對于傳統(tǒng)的數(shù)組,鏈表的一個好處在于,添加或移除元素的時候不需要移動其他元素锐锣。然 而,鏈表需要使用指針,因此實現(xiàn)鏈表時需要額外注意腌闯。數(shù)組的另一個細節(jié)是可以直接訪問任何 位置的任何元素,而要想訪問鏈表中間的一個元素,需要從起點(表頭)開始迭代列表直到找到 所需的元素

3.1.1鏈表的創(chuàng)建
我們使用動態(tài)原型模式來創(chuàng)建一個鏈表。列表最后一個節(jié)點的下一個元素始終是null雕憔。

function LinkedList(){
  function Node(element){
    this.element = element;
    this.next = null;
  }
  this.head = null;
  this.length = 0;
  //通過對一個方法append判斷就可以知道是否設(shè)置了prototype
  if((typeof this.append !== 'function')&&(typeof this.append !== 'string')){
    //添加元素
    LinkedList.prototype.append = function(element){
      var node = new Node(element);
      var current;
      if(this.head === null){
        this.head = node;
      }else{
        current = this.head;
        while(current.next !== null){
          current = current.next;
        }
        current.next = node;
      }
      this.length++;
    };
    //插入元素姿骏,成功true,失敗false
    LinkedList.prototype.insert = function(position,element){
      if(position > -1 && position < this.length){
        var current = this.head;
        var previous;
        var index = 0;
        var node = new Node(element);
        if(position == 0){
          node.next = current;
          this.head = node;
        }else{
          while(index++ < position){
            previous = current;
            current = current.next;
          }
          node.next = current;
          previous.next = node;
        }
        this.length++;
        return true;
      }else{
        return false;
      }
    };
    //根據(jù)位置刪除指定元素斤彼,成功 返回元素分瘦, 失敗 返回null
    LinkedList.prototype.removeAt = function(position){
      if(position > -1 && position < this.length){
        var current = this.head;
        var previous = null;
        var index = 0;
        if(position == 0){
          this.head = current.next;
        }else{
          while(index++ < position){
            previous = current;
            current = current.next;
          }
          previous.next = current.next;
        }
        this.length--;
        return current.element;
      }else{
        return null;
      }
    };
    //根據(jù)元素刪除指定元素蘸泻,成功 返回元素, 失敗 返回null
    LinkedList.prototype.remove = function(element){
      var index = this.indexOf(element);
      return this.removeAt(index);
    };
    //返回給定元素的索引嘲玫,如果沒有則返回-1
    LinkedList.prototype.indexOf = function(element){
      var current = this.head;
      var index = 0;
      while(current){
        if(current.element === element){
          return index;
        }
        index++;
        current = current.next;
      }
      return -1;
    };
    LinkedList.prototype.isEmpty = function(){
      return this.length === 0;
    };
    LinkedList.prototype.size = function(){
      return this.length;
    };
    LinkedList.prototype.toString = function(){
        var string = '';
        var current = this.head;
        while(current){
          string += current.element;
          current = current.next;
        }
        return string;
    };
    LinkedList.prototype.getHead = function(){
      return this.head;
    };
  }
}

3.1.2鏈表的基本使用
var linkedList = new LinkedList();
console.log(linkedList.isEmpty());//true;
linkedList.append('huang');
linkedList.append('du')
linkedList.insert(1,'cheng');
console.log(linkedList.toString());//huangchengdu
console.log(linkedList.indexOf('du'));//2
console.log(linkedList.size());//3
console.log(linkedList.removeAt(2));//du
console.log(linkedList.toString());//huangcheng
3.2.1雙向鏈表的創(chuàng)建
鏈表有多種不同的類型,這一節(jié)介紹雙向鏈表悦施。雙向鏈表和普通鏈表的區(qū)別在于,在鏈表中, 一個節(jié)點只有鏈向下一個節(jié)點的鏈接,而在雙向鏈表中,鏈接是雙向的:一個鏈向下一個元素, 另一個鏈向前一個元素。

雙向鏈表和鏈表的區(qū)別就是有一個tail屬性去团,所以必須重寫insert歼争、append、removeAt方法渗勘。每個節(jié)點對應(yīng)的Node也多了一個prev屬性。

//寄生組合式繼承實現(xiàn)俩莽,詳見javascript高級程序設(shè)計第七章
function inheritPrototype(subType, superType) {
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var prototype = object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
function DoublyLinkedList() {
function Node(element) {
this.element = element;
this.next = null;
this.prev = null;
}
this.tail = null;
LinkedList.call(this);
//與LinkedList不同的方法自己實現(xiàn)旺坠。
this.insert = function(position, element) {
if (position > -1 && position <= this.length) {
var node = new Node(element);
var current = this.head;
var previous;
var index = 0;
if (position === 0) {
if (!this.head) {
this.head = node;
this.tail = node;
} else {
node.next = current;
current.prev = node;
this.head = node;
}
} else if (position == this.length) {
current = this.tail;
current.next = node;
node.prev = current;
this.tail = node;
} else {
while (index++ < position) {
previous = current;
current = current.next;
}
previous.next = node;
node.next = current;
current.prev = node;
node.prev = previous;
}
this.length++;
return true;
} else {
return false;
}
};
this.append = function(element) {
var node = new Node(element);
var current;
if (this.head === null) {
this.head = node;
this.tail = node;
} else {
current = this.head;
while (current.next !== null) {
current = current.next;
}
current.next = node;
node.prev = current;
this.tail = node;
}
this.length++;
};
this.removeAt = function(position) {
if (position > -1 && position < this.length) {
var current = this.head;
var previous;
var index = 0;
if (position === 0) {
this.head = current.next;
if (this.length === 1) {
this.tail = null;
} else {
this.head.prev = null;
}
} else if (position === (this.length - 1)) {
current = this.tail;
this.tail = current.prev;
this.tail.next = null;
} else {
while (index++ < position) {
previous = current;
current = current.next;
}
previous.next = current.next;
current.next.prev = previous;
}
this.length--;
return current.element;
} else {
return false;
}
};
}
inheritPrototype(DoublyLinkedList, LinkedList);
3.2.2雙向鏈表的基本使用
var doublyList = new DoublyLinkedList();
console.log(doublyList.isEmpty()); //true;
doublyList.append('huang');
doublyList.append('du')
doublyList.insert(1, 'cheng');
console.log(doublyList.toString()); //huangchengdu
console.log(doublyList.indexOf('du')); //2
console.log(doublyList.size()); //3
console.log(doublyList.removeAt(2)); //du
console.log(doublyList.toString()); //huangcheng
3.2.3 循環(huán)鏈表
循環(huán)鏈表可以像鏈表一樣只有單向引用,也可以像雙向鏈表一樣有雙向引用。循環(huán)鏈表和鏈 表之間唯一的區(qū)別在于,最后一個元素指向下一個元素的指針(tail.next)不是引用null, 而是指向第一個元素(head)扮超。雙向循環(huán)鏈表有指向head元素的tail.next,和指向tail元素的head.prev取刃。
JavaScript中的“閉包”是什么?請舉一個例子出刷。
閉包是一個可以訪問外部(封閉)函數(shù)作用域鏈中的變量的內(nèi)部函數(shù)璧疗。閉包可以訪問三種范圍中的變量:這三個范圍具體為:(1)自己范圍內(nèi)的變量,(2)封閉函數(shù)范圍內(nèi)的變量馁龟,以及(3)全局變量崩侠。
下面是一個簡單的例子:

  var globalVar = "xyz";

  (function outerFunc(outerArg) {
  var outerVar = 'a';

  (function innerFunc(innerArg) {
   var innerVar = 'b';

  console.log(
  "outerArg = " + outerArg + "\n" +
  "innerArg = " + innerArg + "\n" +
  "outerVar = " + outerVar + "\n" +
  "innerVar = " + innerVar + "\n" +
  "globalVar = " + globalVar);

  })(456);
  })(123);

在上面的例子中,來自于 innerFunc坷檩, outerFunc和全局命名空間的變量都在 innerFunc的范圍內(nèi)却音。因此,上面的代碼將輸出如下:

outerArg = 123
innerArg = 456
outerVar = a
innerVar = b
globalVar = xyz

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末矢炼,一起剝皮案震驚了整個濱河市系瓢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌句灌,老刑警劉巖夷陋,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異胰锌,居然都是意外死亡骗绕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門资昧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爹谭,“玉大人,你說我怎么就攤上這事榛搔∨捣玻” “怎么了东揣?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長腹泌。 經(jīng)常有香客問我嘶卧,道長,這世上最難降的妖魔是什么凉袱? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任芥吟,我火速辦了婚禮,結(jié)果婚禮上专甩,老公的妹妹穿的比我還像新娘钟鸵。我一直安慰自己,他們只是感情好涤躲,可當(dāng)我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布棺耍。 她就那樣靜靜地躺著,像睡著了一般种樱。 火紅的嫁衣襯著肌膚如雪蒙袍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天嫩挤,我揣著相機與錄音害幅,去河邊找鬼。 笑死岂昭,一個胖子當(dāng)著我的面吹牛以现,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播约啊,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼叼风,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了棍苹?” 一聲冷哼從身側(cè)響起无宿,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枢里,沒想到半個月后孽鸡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡栏豺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年彬碱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奥洼。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡巷疼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灵奖,到底是詐尸還是另有隱情嚼沿,我是刑警寧澤估盘,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站骡尽,受9級特大地震影響遣妥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜攀细,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一箫踩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谭贪,春花似錦境钟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鱼的,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間痘煤,已是汗流浹背凑阶。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留衷快,地道東北人宙橱。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像蘸拔,于是被迫代替她去往敵國和親师郑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容