成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

JavaScript中的堆棧 Stack Heap 隊列 數據結構學習 圖片講解

開發 前端
本文主要介紹了JavaScript數組的push()、pop()、shift()和unshift()方法。并且如何通過組合這幾種方法實現類似棧和隊例的行為。
  • 棧(stack) 棧stack為自動分配的內存空間,它由系統自動釋放;
  • 堆(heap) 堆heap是動態分配的內存,大小不定也不會自動釋放。

JavaScript 中的變量分為基本類型和引用類型。

  • 基本類型 (Undefined、Null、Boolean、Number和String)
  • 基本類型在內存中占據空間小、大小固定 ,他們的值保存在棧(stack)空間,是按值來訪問
  • 引用類型 (對象、數組、函數)
  • 引用類型占據空間大、大小不固定, 棧內存中存放地址指向堆(heap)內存中的對象。是按引用訪問的

如下圖所示:棧內存中存放的只是該對象的訪問地址, 在堆內存中為這個值分配空間 。 由于這種值得大小不固定,因此不能把它們保存到棧內存中。但內存地址大小的固定的,因此可以將內存地址保存在棧內存中。 這樣,當查詢引用類型的變量時, 先從棧中讀取內存地址, 然后再通過地址找到堆中的值。

當我們看到一個變量類型是已知的,就分配在棧里面,比如INT,Double等。其他未知的類型,比如自定義的類型,因為系統不知道需要多大,所以程序自己申請,這樣就分配在堆里面。

上方例子得知,當我改變arr2中的數據時,arr1中數據也發生了變化,當改變str1的數據值時,arr1卻沒有發生改變。為什么?這就是傳值與傳址的區別。

因為arr1是數組,屬于引用類型,所以它賦予給arr2的時候傳的是棧中的地址(相當于新建了一個不同名“指針”),而不是堆內存中的對象的值。str1得到的是一個基本類型的賦值,因此,str1僅僅是從arr1堆內存中獲取了一個數值,并直接保存在棧中。arr1、arr2都指向同一塊堆內存,arr2修改的堆內存的時候,也就會影響到arr1,str1是直接在棧中修改,并且不能影響到arr1堆內存中的數據。

數據類型訪問&&復制

基本數據類型:基本數據類型是指保存在棧內存中的簡單數據段。訪問方式是按值訪問。

var a = 1;

a = 2 ;

基本類型變量的復制:從一個變量向一個變量復制時,會在棧中創建一個新值,然后把值復制到為新變量分配的位置上。

var b = a;

vara =newObject();

a.name= 'xz' ;

棧內存&堆內存

為了使程序運行時占用的內存最小,通常要實現垃圾回收機制。

當一個方法執行時,每個方法都會建立自己的內存棧,在這個方法內定義的變量將會逐個放入這塊棧存里,隨著方法的執行結束,這個方法的棧存也將自然銷毀了。因此,所有在方法中定義的變量都是放在棧內存中的;

當我們在程序中創建一個對象時,這個對象將被保存到運行時數據區中,以便反復利用(因為對象的創建成本開銷較大),這個運行時數據區就是堆內存。堆內存中的對象不會隨方法的結束而銷毀,即使方法結束后,這個對象還可能被另一個引用變量所引用(方法的參數傳遞時很常見),則這個對象依然不會被銷毀,只有當一個對象沒有任何引用變量引用它時,系統的垃圾回收機制才會在核實的時候回收它。

思考問題:

demo1.
var a = 1;
var b = a;
b = 2;

// 這時a是?

demo1中在變量對象中的數據發生復制行為時,系統會自動為新的變量分配一個新值。var b = a執行之后,b雖然重新賦值為2,但是他們其實已經是相互獨立互不影響的值了。

demo2.
var m = { a: 1, b: 2 }
var n = m;
n.a = 2;

// 這時m.a的值呢?

demo2中我們通過var n = m執行一次復制引用類型的操作。引用類型的復制同樣也會為新的變量自動分配一個新的值保存在變量對象中,但不同的是,這個新的值,僅僅只是引用類型的一個地址指針。當地址指針相同時,盡管他們相互獨立,但是在變量對象中訪問到的具體對象實際上是同一個。因此當我改變n時,m也發生了變化。這就是引用類型的特性。

堆棧和隊列

要了解JavaScript數組的堆棧和隊列方法的操作,需要先對堆棧和隊列基礎知識有所了解。在繼續看后面的內容之前,我們先簡單地了解一下堆棧和隊列的概念。

棧和隊列都是動態的集合,在棧中,可以去掉的元素是最近插入的那一個。棧道實現了后進先出。在隊列中,可以去掉的元素總是在集合中存在的時間最長的那一個。隊列實現了先進先出的策略。

堆棧的基本概念

先上張圖:

棧是一種LIFO(Last-In-First-Out,后進先出)的數據結構,也就是最新添加的項最早被移除。而棧中項的插入(叫做推入)和移除(叫做彈出),只發生在一個位置——棧的頂部。

最開始棧中不含有任何數據,叫做空棧,此時棧頂就是棧底。然后數據從棧頂進入,棧頂棧底分離,整個棧的當前容量變大。數據出棧時從棧頂彈出,棧頂下移,整個棧的當前容量變小。

比如說,我們在一個箱子中放了很多本書,如果你要拿出第二本書,那么你要先把第一本書拿出來,才能拿第二本書出來;拿出第二本書之后,再把第一本書放進去。

ECMAScript為數組專門提供了 push() 和 pop() 方法,以便實現類似的行為。 push() 方法可以接收任意數量的參數,把它們逐個添加到數組末尾,并返回修改后數組的長度。而 pop() 方法則從數組末尾移除最后一項,減少數組的length值,然后返回移除的項。

隊列的基本概念

棧數據結構的訪問規則是LIFO(后進先出),而隊列數據結構的訪問規則是FIFO(Fist-In-First-Out,先進先出)。隊列在列表的末端添加項,從列表的前端移除項。如下圖所示:

比如說火車站排隊買票,先到的先買,買好的先走。

入隊列操作其實就是在隊尾追加一個元素,不需要任何移動,時間復雜度為O(1)。出隊列則不同,因為我們已經架設下標為0的位置是隊列的隊頭,因此每次出隊列操作所有元素都要向前移動。如下圖所示:

ECMAScript為數組專門提供了 shift() 和 unshift() 方法,以便實現類似隊列的行為。由于 push() 是向數組末端添加數組項的方法,因此要模擬隊列只需一個從數組前端取得數組項的方法。實現這一操作的數組方法就是 shift() ,它能夠移除數組中的第一個項并返回該項,同時將數組長度減1。

顧名思義, unshift() 與 shift() 的用途相反:它能在數組前端添加任意個數組項并返回新數組的長度。因此,同時使用 unshift() 和 pop() 方法,可以從相反的方向來模擬隊列,即在數組的前端添加數組項,從數組末端移除數組項。

push()方法

該方法是向數組末尾添加一個或者多個元素,并返回新的長度。

push()方法可以接收任意數量的參數,把它們逐個添加到數組的末尾,并返回修改后數組的長度。如:

var arr = []; //創建一個空數組
console.log(arr); // []
console.log("入棧"); // 入棧
arr.push(1); // 將1添加到數組arr中
console.log(arr); // [1]
arr.push(2); //將2添加到數組arr中
console.log(arr); //[1,2]
arr.push([3,4]); // 將數組[3,4]添加到arr中
console.log(arr); // [1,2,[3,4]]
console.log(arr.length); // 3

在Chrome瀏覽器控制臺輸出的效果如下圖所示:

pop()方法

pop()方法剛好和push()方法相反。pop()方法刪除數組的最后一個元素,把數組的長度減1,并且返回它被刪除元素的值,如果數組變為空,則該方法不改變數組,返回undefine值。如下代碼演示:

var arr = [1,2,3,4]; //創建一個數組
console.log(arr); // [1,2,3,4]
console.log(arr.length); // 4
console.log("出棧,后進先出"); // 出棧,后進先出
arr.pop();
console.log(arr); // // [1,2,3]
arr.pop();
console.log(arr); // [1,2]
arr.pop();
console.log(arr); // [1]
arr.pop();
console.log(arr); // []

在Chrome瀏覽器控制臺輸出的效果如下圖所示:

unshift()方法

unshift()方法是向數組的開頭添加一個或多個元素,并且返回新的長度。

var arr = []; //創建一個空的數組
console.log(arr); // []
console.log("入隊"); // 入隊
arr.unshift(1,2,3,4); // 將1,2,3,4推入到數組arr
console.log(arr); // [1,2,3,4]
console.log(arr.length); // 4

在Chrome瀏覽器控制臺輸出的效果如下圖所示:

shift()方法

shift()方法和unshift()方法恰恰相反。該方法用于把數組的第一個元素從其中刪除,并返回被刪除的值。如果數組是空的,shift()方法將不進行任何操作,返回undefined的值。

var arr = [1,2,3,4]; // 創建一個數組
console.log(arr); // [1,2,3,4]
arr.shift(); // 取得第一項
console.log(arr); // [2,3,4]
arr.shift(); // 取得第一項
console.log(arr); // [3,4]
arr.shift(); // 取得第一項
console.log(arr); // [4]
arr.shift(); // 取得第一項
console.log(arr); // []

在Chrome瀏覽器控制臺輸出的效果如下圖所示:

簡單得回憶一下:

  • push()方法可以在數組的末屬添加一個或多個元素
  • shift()方法把數組中的第一個元素刪除
  • unshift()方法可以在數組的前端添加一個或多個元素
  • pop()方法把數組中的最后一個元素刪除

JavaScript實現類似棧和隊列的行為

了解這幾種方法之后,我們就可以將它們結合起來,輕松的實現類似棧和隊列的行為。

實現類似棧的行為

將push()和pop()結合在一起,我們就可以實現類似棧的行為:

//創建一個數組來模擬堆棧
var a=new Array();
console.log(a);
//push: 在數組的末尾添加一個或更多元素,并返回新的長度
console.log("入棧");
a.push(1)
console.log(a);//----->1
a.push(2);
console.log(a);//----->1,2
a.push(3);
console.log(a);//----->1,2,3
a.push(4);
console.log(a);//----->1,2,3,4
console.log("出棧,后進先出");
console.log(a);
//pop:從數組中把最后一個元素刪除,并返回這個元素的值
a.pop();//----->4
console.log(a);
a.pop();//----->3
console.log(a);
a.pop();//----->2
console.log(a);
a.pop();//----->1
console.log(a);

在Chrome瀏覽器控制臺輸出的效果如下圖所示:

實現類似隊列的行為

將shift()和push()方法結合在一起,可以像使用隊列一樣使用數組。即在數組的后端添加項,從數組的前端移除項:

//創建一個數組來模擬隊列
var a=new Array();
console.log(a);
//push: 在數組的末尾添加一個或更多元素,并返回新的長度
console.log("入隊");
a.push(1)
console.log(a);//----->1
a.push(2);
console.log(a);//----->1,2
a.push(3);
console.log(a);//----->1,2,3
a.push(4);
console.log(a);//----->1,2,3,4
console.log("出隊,先進先出");
console.log(a);
//shift:從數組中把第一個元素刪除,并返回這個元素的值
a.shift();//----->1
console.log(a);
a.shift();//----->2
console.log(a);
a.shift();//----->3
console.log(a);
a.shift();//----->4
console.log(a);

在Chrome瀏覽器控制臺輸出的效果如下圖所示:

除此之外,還可以同時使用unshift()和pop()方法,從相反的方向來模擬隊列,即在數組的前端添加項,從數組的后端移除項。如下面的示例所示:

//創建一個數組來模擬隊列
var a=new Array();
console.log(a);
//unshift: 在數組的前端添加一個或更多元素,并返回新的長度
console.log("入隊");
a.unshift(1)
console.log(a);//----->1
a.unshift(2);
console.log(a);//----->2,1
a.unshift(3);
console.log(a);//----->3,2,1
a.unshift(4);
console.log(a);//----->4,3,2,1
console.log("出隊,先進先出");
console.log(a);
//pop:從數組中把最一個元素刪除,并返回這個元素的值
a.pop();//----->4
console.log(a);
a.pop();//----->3
console.log(a);
a.pop();//----->2
console.log(a);
a.pop();//----->1
console.log(a);

在Chrome瀏覽器控制臺輸出的效果如下圖所示:

push()方法和unshift()方法的性能測試

Array的push()與unshift()方法都能給當前數組添加元素,不同的是,push()是在末尾添加,而unshift()則是在開頭添加,從原理就可以知道,unshift()的效率是較低的。原因是,它每添加一個元素,都要把現有元素往下移一個位置。但到底效率差異有多大呢?下面來簡單測試一下。

/*
關于代碼中"var s=+newDate();"的技巧說明
解釋如下:=+這個運算符是不存在的;
+相當于.valueOf();
+new Date()相當于new Date().valueOf()
//4個結果一樣返回當前時間的毫秒數
alert(+new Date());
alert(+new Date);
var s=new Date();
alert(s.valueOf());
alert(s.getTime());
*/
var arr = [ ];
var startTime = +new Date(); //+new Date()相當于new Date().valueOf(),返回當前時間的毫秒數
// push性能測試
for (var i = 0; i < 100000; i++) {
  arr.push(i);
}
var endTime = +new Date();
console.log("調用push方法往數組中添加100000個元素耗時"+(endTime-startTime)+"毫秒");

startTime = +new Date();
arr = [ ];
// unshift性能測試
for (var i = 0; i < 100000; i++) {
  arr.unshift(i);
}
endTime = +new Date();
console.log("調用unshift方法往數組中添加100000個元素耗時"+(endTime-startTime)+"毫秒");

這段代碼分別執行了100000次push()和unshift()操作,在chrome瀏覽器運行一次,得到的結果如下圖所示:

可見,unshift()比push()要慢差不多100倍!因此,平時還是要慎用unshift(),特別是對大數組。那如果一定要達到unshift()的效果,可以借助于Array的reverse()方法,Array的reverse()的方法能夠把一個數組反轉。先把要放進數組的元素用push()添加,再執行一次reverse(),就達到了unshift()的效果。比如:

//創建一個數組來模擬堆棧
var a=new Array();
//使用push方法在數組的末尾添加元素
a.push(1)
a.push(2);
a.push(3);
a.push(4);
console.log("數組反轉之前數組中的元素順序");
console.log(a);//----->1,2,3,4
//Array有一個叫做reverse的方法,能夠把一個數組反轉。先把要放進數組的元素用push添加,再執行一次reverse,就達到了unshift的效果
a.reverse();//使用reverse方法將數組進行反轉
console.log("數組反轉之后數組中的元素順序");
console.log(a);

在chrome瀏覽器控制臺輸出的效果如下圖所示:

從運行結果來看,數組元素的順序已經反轉過來了。

reverse()方法的性能測試;

var arr = [ ], s = +new Date; 
for (var i = 0; i < 100000; i++) {
   arr.push(i);
}
//調用reverse方法將數組里面的100000元素的順序反轉
arr.reverse();
console.log("調用reverse方法將數組里面的100000元素的順序反轉耗時:"+(+new Date - s)+"毫秒");

在chrome瀏覽器控制臺輸出的效果如下圖所示:

從運行效果中可以看到,reverse()方法的性能極高,可以放心使用。

總結

本文主要介紹了JavaScript數組的push()、pop()、shift()和unshift()方法。并且如何通過組合這幾種方法實現類似棧和隊例的行為。

1.js中刪除堆棧:

js中的splice方法。

splice(index,len,[item]) 注釋:該方法會改變原始數組。

splice有3個參數,它也可以用來替換/刪除/添加數組內某一個或者幾個值。

index:數組開始下標 len: 替換/刪除的長度 item:替換的值,刪除操作的話 item為空。

如:arr = ['a','b','c','d']

刪除 ---- item不設置

arr.splice(1,1) //['a','c','d'] 刪除起始下標為1,長度為1的一個值,len設置的1,如果為0,則數組不變

arr.splice(1,2) //['a','d'] 刪除起始下標為1,長度為2的一個值,len設置的2

替換 ---- item為替換的值

arr.splice(1,1,'ttt') //['a','ttt','c','d'] 替換起始下標為1,長度為1的一個值為‘ttt’,len設置的1

arr.splice(1,2,'ttt') //['a','ttt','d'] 替換起始下標為1,長度為2的兩個值為‘ttt’,len設置的1

添加 ---- len設置為0,item為添加的值

arr.splice(1,0,'ttt') //['a','ttt','b','c','d'] 表示在下標為1處添加一項‘ttt’

看來還是splice最方便啦

2:delete delete刪除掉數組中的元素后,會把該下標出的值置為undefined,數組的長度不會變

如:delete arr[1] //['a', ,'c','d'] 中間出現兩個逗號,數組長度不變,有一項為undefined

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2022-09-01 16:27:19

JavaScriptWeb開發

2011-04-11 12:48:36

隊列數據結構C++

2011-04-11 11:23:17

隊列數據結構

2021-03-29 08:01:20

JavaScript數據結構

2011-04-11 12:22:11

數據結構C++

2011-04-11 17:09:37

稀疏矩陣矩陣C++

2021-01-06 08:03:00

JavaScript數據結構

2021-01-28 07:33:34

JavaScript鏈表數據

2014-04-04 11:14:18

JavaScriptStack遞歸

2021-07-16 07:57:34

Python數據結構

2010-07-19 11:07:13

Perl控制結構

2020-09-28 08:11:14

JavaScript數據

2009-08-13 16:02:29

C#結構

2020-08-10 14:46:30

JavaScriptStack

2018-06-13 08:53:39

HadoopHBase存儲

2021-03-12 09:13:47

Java數據結構算法

2024-02-19 16:23:11

2020-12-17 10:12:33

數據結構算法隊列

2020-08-03 07:48:15

Javascript數據結構

2021-03-09 06:30:32

JAVA數據結構算法
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 瑟瑟视频在线看 | 国产一区久久 | 成人三级影院 | 美国黄色毛片 | 欧美精品一区二区在线观看 | 99精品欧美一区二区蜜桃免费 | 精精国产xxxx视频在线播放7 | 亚洲五码久久 | 久久亚洲美女 | 成人综合一区二区 | 一级免费毛片 | 亚洲欧美日韩在线一区二区 | 午夜网站视频 | 欧美一级久久 | 91精品国产手机 | 国产精品揄拍一区二区 | 欧美成人精品一区二区男人看 | www.干| 亚洲 欧美 日韩在线 | 日本精品视频在线 | 成人性视频在线 | 97日日碰人人模人人澡分享吧 | 欧美精品成人一区二区三区四区 | 99自拍视频 | 欧美在线一级 | 91在线精品视频 | 国产一二区在线 | 欧美激情一区二区三级高清视频 | 国产精品片 | 久久视频免费观看 | 亚洲热在线视频 | 一区二区高清在线观看 | 亚洲欧美一区二区三区1000 | 偷拍亚洲色图 | 欧美日韩久久久久 | 国产欧美久久精品 | 97国产超碰 | 日韩午夜场 | 日韩在线视频一区 | 日韩成人精品在线观看 | 久久国产精品一区二区 |