翻閱《數據結構與算法javascript描述》--數組篇

導讀:

這篇文章比較長,介紹了數組常見的操做方法以及一些注意事項,最後還有幾道經典的練習題(面試題)。javascript

 

數組的定義:

JavaScript 中的數組是一種特殊的對象,用來表示偏移量的索引是該對象的屬性,索引多是整數。然而,這些數字索引在內部被轉換爲字符串類型,這是由於 JavaScript 對象中的屬性名必須是字符串。在內部被歸類爲數組。因爲 Array 在 JavaScript 中被看成對象,所以它有許多屬性和方法能夠在編程時使用。java

使用數組:

1.建立數組面試

  • 使用 [] 操做符 ,var arr=[] ,該方法效率最高。
  • 調用 Array 的構造函數建立數組,var myArr=new Arrery()

2.讀寫數組正則表達式

3.由字符串生成數組,調用字符串對象的split()方法。算法

split() 方法經過把字符串分割成子字符串來把一個 String 對象分割成一個字符串數組。編程

   str.split([separator][, limit])數組

separator指定用來分割字符串的字符(串)。separator 爲一個字符串或正則表達式。數據結構

  • 當忽略 separator,返回整個字符串的數組。
  • 當 separator 是空字符串, str 將會把原字符串中每一個字符的數組形式返回。

limit【可選】一個整數,限定返回的分割片斷數量,返回的數組截取最多 limit 個元素。app

/*
 * 定義了一個函數:使用指定的分隔符將一個字符串分割成一個字符串數組。分隔字符串後,
 * 該函數依次輸出原始字符串信息,被使用的分隔符,返回數組元素的個數,以及返回數組中全部的元素。
 */
function splits(str, separator) {
    var afterString = str.split(separator);
    console.log('分割前的字符串 : "' + str + '"');
    console.log('separator : "' + separator + '"');
    console.log('分割後獲得:');
    for (var i = 0; i < afterString.length; i++)
        console.log(afterString[i] + " , ");
}

var eg1 = "hello world";
var eg2 = "a,b,c,d";
var eg3 = "";//將str定義爲一個空字符串,
var eg1separator = " "; //separator爲空字符串時,str 將被轉換爲由字符串中字符組成的一個數組。var eg2separator = ",";
var eg2separator = ",";
splits(eg1, eg1separator);
splits(eg1, eg2separator);
splits(eg1);//忽略 separator,則返回整個字符串的數組形式。

splits(eg2, eg2separator);
splits(eg3);//返回一個包含一個空字符串的數組,而不是一個空數組。

 

4.對數組的總體性操做:(面試題之一)函數

淺複製:將數組a賦值給數組b,此時的數組b只是對數組a的引用,當數組a發生改變時,數組b也隨着發生改變。

var a=[];
for(var i=0;i< 5;i++){
    a[i]=i;
}

var b=a;
console.log(a[1]);
console.log(b[1]);//賦值引用前 1

a[1]=999;
console.log(a[1]);
console.log(b[1]);//賦值引用後 999

深複製:能夠封裝一個copy()方法。

 

存取數組:

1.查找元素:indexOf()   lastIndexOf()

indexOf() 方法返回指定值在字符串對象中首次出現的位置。從 fromIndex 位置開始查找,若是不存在,則返回 -1。

   str.indexOf(searchValue[, fromIndex])

searchValue 表示被查找的值。

fromIndex 【可選】表示調用該方法的字符串中開始查找的位置。能夠是任意整數。默認值爲 0。

  • fromIndex < 0 ,查找整個字符串。
  • fromIndex >= str.length,該方法返回 -1,但當被查找的字符串是一個空字符串,此時返回 str.length。
/*
 * 從左向右索引。首字符索引(index)爲 0,最後一個字符索引是 stringName.length - 1。
 */
"hello world".indexOf("hello");        // returns  0
"hello world hello".indexOf("hello");  // returns  0  由於是返回首次出現的位置
"hello world".indexOf("world", 0);     // returns  6
"hello world".indexOf("world", 999);   // returns  -1
"hello world".indexOf("", 10);         // returns  10
"hello world".indexOf("", 999);        // returns  11


/*
 * indexOf 方法區分大小寫。例如,下面的表達式返回 -1:
 */
"hello world".indexOf("Hello");    // returns -1


/*
 * 檢測是否存在某字符串
 */
"hello world".indexOf("hello") !== -1;   // true
"hello world".indexOf("hel") !== -1;     // false

 

2.數組的字符串表示:將數組轉化爲字符串:join()  toString()

join() 方法將數組中的全部元素鏈接成一個字符串。(若是元素是undefined 或者null, 則會轉化成空字符串。)

   str = arr.join([separator = ','])

separator【可選】,指定鏈接每一個數組元素的分隔符。分隔符會被轉成字符串類型;

  • seprator省略時,默認爲一個逗號。
  • seprator爲一個空字符串時,直接鏈接數組中的全部元素。
/*
 * 使用四種不一樣的分隔符鏈接數組元素。
 * 首先建立了一個數組 arr,包含有三個元素,而後用四種不一樣的分隔符鏈接全部數組元素。
 * 首先是默認的分隔符逗號,而後是一個逗號加空格,接下來是一個加號先後加空格,最後是一個空字符串。
 */
var arr = ['Apple', 'Banner', 'Orange'];
var eg1 = arr.join();        // eg1的值變爲"Apple,Banner,Orange"
var eg2 = arr.join(', ');    // eg2的值變爲"Apple, Banner, Orange"
var eg3 = arr.join(' + ');   // eg3的值變爲"Apple + Banner + Orange"
var eg4 = arr.join('');      // eg4的值變爲"AppleBannerOrange"

 

 toString() 方法返回一個表示當前函數源代碼的字符串,也就是把一個值轉換爲字符串。

    function.toString()

Function 對象覆蓋了從 Object 繼承來的 Object.prototype.toString 方法,包括 function關鍵字,形參列表,大括號,以及函數體中的內容。

在函數須要轉換爲字符串時,通常會自動調用函數的 toString 方法。

看到這裏的toString(),我想起了toString()  與valueof() 的隱式調用。不嚴謹的說,當須要計算時,會隱式調用valueof()。當處於字符串環境時須要顯示數據或者結果時會調用toString()。有興趣的同窗能夠google一下。

 

3.由已有的數組建立新數組:

concat()方法合併已有的多個數組,建立新數組

splice()方法截取出一個數組的子集建立新數組

 

concat() 方法將傳入的數組或非數組值與原數組合並,組成一個新的數組並返回.

   var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])

valueN 須要與原數組合並的數組或非數組值。

concat 方法建立一個新的數組,不修改調用它的對象和參數中的各個數組的值,而是將他們的每一個元素拷貝一份放在組合成的新數組中。有兩種拷貝的方式:

  • 對象引用(非對象直接量):複製對象引用放到組合的新數組裏,原數組和新數組都引用同一個實際的對象,當實際的對象被修改時,兩個數組都會被修改。
  • 字符串和數字: 複製字符串和數字的值放到新數組裏.

 concat 方法鏈接一個或多個數組(值)不會改變本來的數組/值。

/*
 * 鏈接兩個數組,兩個數組合併爲一個新數組:
 */
var arr1 = ["a", "b", "c"];
var arr2 = [1, 2, 3];
console.log(arr1.concat(arr2)); // ["a", "b", "c", 1, 2, 3]


/*
 * 三個數組合併爲一個新數組
 */
var num1 = [1, 2, 3];
var num2 = [4, 5, 6];
var num3 = [7, 8, 9];
console.log(num1.concat(num2, num3)); // [1, 2, 3, 4, 5, 6, 7, 8, 9]


/*
 * 將非數組值合併到數組裏,多個數組和多個非數組值合併爲一個新數組
 */
var myArr = ['a', 'b', 'c'];
console.log(myArr.concat(1, [2, 3]));  // ["a", "b", "c", 1, 2, 3]

固然,除上面以外,對concat方法,ES6跟ES7都有支持,有興趣的同窗自行google

 

splice() 方法用新元素替換舊元素,以此修改數組的內容。

    array.splice(start, deleteCount[, item1[, item2[, ...]]])

start​ 從數組開始修改的位置。

  • 超出數組的長度,從數組末尾開始添加;
  • 負值,表示從數組末位開始的第幾位。

deleteCount整數,表示要移除的數組元素的個數。

  • deleteCount 是 0,不移除元素。表示應該至少應添加一個新元素。
  • deleteCount 大於start 以後的元素的總數,則從 start 後面的元素都被刪除(含第 start 位)。

itemN 要添加進數組的元素。不指定時, splice() 只刪除數組元素。

注意,splice()與 slice()是不一樣的,splice() 方法會直接對數組進行修改。

var num = ["one", "tow", "three", "four"];
//從第2位開始刪除0個元素,插入"insert",至關於增長的方法
num.splice(2, 0, "insert");  // ["one", "tow", "insert", "three", "four"]

//從第3位開始刪除1個元素
num.splice(3, 1);   // ["one", "tow", "insert", "four"]

 

可變函數:

1.爲數組增添元素:push()方法將元素增添至末尾, unshift()將元素增添至開頭

push() 方法添加一個或多個元素到數組的末尾,並返回數組新的長度(length 屬性值)。

   arr.push(element1, ..., elementN)

var arr = ["a", "b"];
arr.push("c", "d");
console.log(arr);   // ["a", "b", "c", "d"]

 

unshift() 方法在數組的開頭添加一個或者多個元素,並返回數組新的 length 值。

   arr.unshift(element1, ..., elementN)

var arr = [1, 2];

arr.unshift(0);        // [0, 1, 2]
arr.unshift(-2, -1);   // [-2, -1, 0, 1, 2]
arr.unshift([-3]);     // [[-3], -2, -1, 0, 1, 2]

 

2.從數組中刪除元素:pop() 方法能夠刪除數組末尾的元素,  Shift() 方法能夠刪除數組的第一個元素

pop() 方法刪除一個數組中的最後的一個元素,而且返回這個元素。

   array.pop()

var arr = ["a", "b", "c"];
console.log(arr.pop());  // 刪除了最後一個 c

 

shift() 方法刪除數組的 第一個 元素,並返回這個元素。該方法會改變數組的長度。

   arr.shift()

若是 length 屬性的值爲 0 (長度爲 0),則返回 undefined。

var arr = ["a", "b", "c"];
console.log(arr.shift());  // 刪除了第一個 a

 

3.從數組中間位置添加和刪除元素:splice()

 上面提過了。

 

4.數組排序:正序(字典順序):sort(),   倒序;reverse()

sort() 方法對數組的元素作原地的排序,並返回該數組。 默認按照字符串的Unicode碼位點(code point)排序。

   arr.sort([compareFunction])

compareFunction【可選】用來指定按某種順序進行排列的函數。

/**
 * compareFunction省略時,元素被轉換爲字符串並按照萬國碼位點順序排序。
 */
var words = ['one', 'three', 'four'];
console.log(words.sort()); // [ 'four', 'one', 'three' ]

var num = [100, 10, 3, 21];
console.log(num.sort()); // 按字典正排序獲得:[10, 100, 21, 3]

/**
 * 指明compareFunction時,數組會按照調用該函數的返回值排序。記 a 和 b 是兩個將要被比較的元素
 * 當compareFunction(a, b) < 0 , a 被排列到 b 以前;
 * 當compareFunction(a, b) = 0 , a 和 b 的相對位置不變;
 * 當compareFunction(a, b) > 0 , b 被排列到 a 以前;
 * 當compareFunction(a, b) 必須老是對相同的輸入返回相同的比較結果,不然排序的結果將是不肯定的。
 */
var nums = [4, 2, 5, 1, 3];
nums.sort(function (a, b) {
    return b - a;
});
console.log(nums);// [ 5, 4, 3, 2, 1 ]


/**
 * 下面建立四個數組
 * 展現原數組,對數組進行排序,對比數字數組指定與不指定 compareFunction 狀況下的結果。
 */
var eg1 = ["cat", "dog", "bear"];
var eg2 = ["80", "9", "700"];
var eg3 = [40, 1, 5, 200];
var eg4 = ["80", "9", "700", 40, 1, 5, 200];// 當使用比較函數後,數字數組會按照數字大小排序。
function compare(a, b) {
    return a - b;
}

console.log('eg1:', eg1.join());
console.log('排序後:', eg1.sort());

console.log('eg2:', eg2.join());
console.log('沒有使用比較函數:', eg2.sort());
console.log('使用比較函數:', eg2.sort(compare));

console.log('eg3:', eg3.join());
console.log('沒有使用比較函數:', eg3.sort());
console.log('使用比較函數:', eg3.sort(compare));

console.log('eg4:', eg4.join());
console.log('沒有使用比較函數:', eg4.sort());
console.log('使用比較函數:', eg4.sort(compare));

映射優化:

當元素較多的時候,compareFunction 可能會有很高的負載,使用 map 輔助排序。首先將數組中的每一個元素比較的實際值取出來,排序後再將數組恢復。

 

迭代器:

對數組的每一個元素運用一個函數,能夠返回一個值,一組值或一個新數組

  • 不生成新數組的迭代方法; forEach()  every()  some()  reduce()
  • 生成新數組的迭代方法;:map() 和 filter()。

 

map() 方法返回一個由原數組中的每一個元素調用一個指定方法後的返回值組成的新數組。

   array.map(callback[, thisArg])

callback函數返回3個參數

  • currentValue 第一個參數,數組中當前被傳遞的元素。
  • index 第二個參數,數組中當前被傳遞的元素的索引。
  • array 第三個參數,調用 map 方法的數組,通常指原數組自己。

thisArg 【可選】 callback 函數時 this 指向的對象,省略或者賦值爲 null 或 undefined,則 this 指向全局對象 。

map 方法會給原數組中的每一個元素都按順序調用一次 callback 函數。callback 每次執行後的返回值組合起來造成一個新數組。callback 函數只會在有值的索引上被調用;那些歷來沒被賦過值或者使用 delete 刪除的索引則不會被調用。

/*
 * 求數組中每一個元素的平方根
 */
var numbers = [1, 4, 9];
numbers.map(Math.sqrt);   // [1, 2, 3]


/*
 * 通常狀況下,map 方法中的 callback 函數只接受一個參數,就是正在被遍歷的數組元素自己。
 * 但某些狀況下傳入不止一個參數。這讓咱們很容易犯錯誤。
 */
["1", "2", "3"].map(parseInt);   // [1, NaN, NaN]
// 或許不少人一開始認爲返回[1, 2, 3],緣由本身去google。

 

filter() 方法使用指定的函數測試全部元素,並建立一個包含全部經過測試的元素的新數組。

   arr.filter(callback[, thisArg])

callback 用來測試數組的每一個元素的函數。

傳入三個參數:

  1. 元素的值
  2. 元素的索引
  3. 被遍歷的數組

thisArg 【可選】執行 callback 時的用於 this 的值。

/*
 * 篩選大於某一指定值
 */
function isBig(element) {
    return element <= 100;
}

[12, 5, 8, 130, 44].filter(isBig);  // [ 12, 5, 8, 44 ]

 

二維和多維數組:

1.建立二維數組

JavaScript 只支持一維數組,可是經過在數組裏保存數組元素的方式,能夠建立多維數組。二維數組相似由行和列構成的數據表格。在 JavaScript 中建立二維數組,先建立一個數組,而後讓數組的每一個元素也是一個數組。

這裏 經過擴展數組對象增長一個新方法,該方法設定數組的行數、列數和初始值。下面是這個方法的定義(引用JavaScript: The Good Parts(O’Reilly)一書的一段代碼):

Array.matrix = function (numrows, numcols, initial) {
    var arr = [];
    for (var i = 0; i < numrows; ++i) {
        var columns = [];
        for (var j = 0; j < numcols; ++j) {
            columns[j] = initial;
        }
        arr[i] = columns;
    }

2.處理方式i:使用嵌入式的for循環

 

對象數組:

數組除了包含基本數據類型元素(數字,字符串)還包含對象,數組的方法和屬性對對象依然適用。在對象中,可使用數組存儲複雜的數據。

 

 小練習

1. 篩選數組中最大值與最小值

/*
 * 秉承着儘可能本身封裝方法的思想,
 * 利用快速排序得出正序排列的數組後;
 * 最小值爲最左邊的數,最大值爲最右邊的數。
 */
function quickSort(arr, left, right) {
    function swap(arr, a, b) {
        var temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

    //原地分區算法
    function partition(arr, left, right) {
        var pivot = arr[right];
        var storeIndex = left;
        for (var i = left; i < right; i++) {
            if (arr[i] < pivot) {
                swap(arr, storeIndex, i);
                storeIndex++;
            }
        }

        swap(arr, right, storeIndex);
        return storeIndex;
    }

    function sort(arr, left, right) {
        if (left > right) return;

        var storeIndex = partition(arr, left, right);
        sort(arr, left, storeIndex - 1);
        sort(arr, storeIndex + 1, right);
    }

    sort(arr, 0, arr.length - 1);
    return arr;
}

var arry = [1, 20, 2, 8];
quickSort(arry);
console.log(quickSort(arry));   // [ 1, 2, 8, 20 ]

var max = arry[arry.length - 1];
var min = arry[0];
console.log(max);       // 20
console.log(min);       // 1

 

2. 對一個數組,指定某一元素,刪除它並返回新數組

/*
 *  這裏簡單用到一個splice()方法
 */
function deletes(arr, target) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] == target) {
            arr.splice(i, 1)
        }
    }
    return arr;
}

var arr = ['as',88, '0uou','88'];
console.log(deletes(arr, 88));         // [ 'as',  '0uou' ]

// 我刪除數字 88 ,它把個人字符串‘88’也刪除了。
// 這裏就是上文提到過的隱式地調用了toString方法
// 解決方法就是加入一個類型判斷,這裏我就再也不提供代碼了。

 

3. 判斷某一數組中是否存在相同的元素

/*
 * 我這裏提供一個參考,固然更好的方法是利用哈希表
 */
function isSame(arr) {
    var store = arr;
    for (var i = 0; i < arr.length; i++) {
        for (var k = i + 1; k < store.length; k++) {
            if (store[k] == arr[i]) {
                return true
            }
        }
    }
    return false
}

var a = isSame([1, 7, 7, 9]);
console.log(a);    // true

 

4. 數組去重(最優解)

function unique(arr) {
    var hash = {},
        result = [],
        type = '',
        item;

    for (var i = 0; i < arr.length; i++) {
        item = arr[i];
// 判斷類型 type
= Object.prototype.toString.apply(item); if (!hash[item + type]) { hash[item + type] = true; result.push(item); } } return result; } var testArr = [1, 'null', null, null, undefined, undefined, 2, 1, '2', 3, NaN, NaN, {"name": 1}, {"name": 2}, {"name": 1}]; console.log(unique(testArr)); // [ 1, 'null', null, undefined, 2, '2', 3, NaN, { name: 1 } ]

很遺憾,這還不是最完美的答案,由於不能正確區分對象。

文章已經很長了,這裏我將會單獨整理出來一篇博客:

      面試整理之數組去重

到時你們能夠去看看。

 

小結:

上面介紹了那麼多種方法,你們可能都看混亂了吧,下面簡單總結下這些方法:

  • 棧和隊列的實現:.pop, .push, .shift,和 .unshift
  • 判斷:.some和.every
  • 分割字符串:.split
  • 增長與刪除(最強大).splice
  • 查找:.indexOf .lastIndexOf
  • 字符串拼接.join和.concat
  • 模型映射:.map
  • 過濾查詢:.filter
  • 正序:.sort
  • 計算:.reduce和.reduceRight
  • 複製:.slice
  • 倒序.reverse
  • 循環:.forEach

 

 

注意:本篇是我翻閱《數據結構與算法javascript描述》後,本身所寫的小結,須要對javascript深刻學習的同窗,還需看原書。初學者能夠以此做爲學習的大綱。至於好厲害的人,忽略本文,固然能夠提建議,我定當修改。

本系列文章會持續更新。

相關文章
相關標籤/搜索