《数据结构与算法javascript描述》--数组篇

导读:

这篇文章比较长,介绍了数组常见的操作方法以及一些注意事项,最后还有几道经典的练习题(面试题)。

数组的定义:

JavaScript 中的数组是一种特殊的对象,用来表示偏移量的索引是该对象的属性,索引可能是整数。然而,这些数字索引在内部被转换为字符串类型,这是因为 JavaScript 对象中的属性名必须是字符串。在内部被归类为数组。由于 Array 在 JavaScript 中被当作对象,因此它有许多属性和方法可以在编程时使用。

使用数组:

1.创建数组

  • 使用 [] 操作符 ,var arr=[] ,该方法效率最高。
  • 调用 Array 的构造函数创建数组,var myArr=new Arrery()

2.读写数组

3.由字符串生成数组,调用字符串对象的split()方法。

split() 方法通过把字符串分割成子字符串来把一个 String 对象分割成一个字符串数组。

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

separator指定用来分割字符串的字符(串)。separator 为一个字符串或正则表达式。

  • 当忽略 separator,返回整个字符串的数组。
  • 当 separator 是空字符串, str 将会把原字符串中每个字符的数组形式返回。

limit【可选】一个整数,限定返回的分割片段数量,返回的数组截取最多 limit 个元素。

/*
* 定义了一个函数:使用指定的分隔符将一个字符串分割成一个字符串数组。分隔字符串后,
* 该函数依次输出原始字符串信息,被使用的分隔符,返回数组元素的个数,以及返回数组中所有的元素。
*/
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深入学习的同学,还需看原书。初学者可以以此作为学习的大纲。至于好厉害的人,忽略本文,当然可以提建议,我定当修改。

本系列文章会持续更新。

https://github.com/LYZ0106/

数据结构与算法javascript描述的更多相关文章

  1. 《数据结构与算法JavaScript描述》

    <数据结构与算法JavaScript描述> 基本信息 作者: (美)Michael McMillan 译者: 王群锋 杜欢 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:9 ...

  2. 翻阅《数据结构与算法javascript描述》--数组篇

    导读: 这篇文章比较长,介绍了数组常见的操作方法以及一些注意事项,最后还有几道经典的练习题(面试题). 数组的定义: JavaScript 中的数组是一种特殊的对象,用来表示偏移量的索引是该对象的属性 ...

  3. 列表的实现-----数据结构与算法JavaScript描述 第三章

    实现一个列表 script var booklist = new List(); booklist.append('jsbook'); booklist.append('cssbook'); book ...

  4. 《数据结构与算法JavaScript描述》中的一处错误

    最近在看<数据结构与算法JavaScript描述>这本书,看到选择排序这部分时,发现一个比较大的错误. 原书的选择排序算法是这样的: function selectionSort() { ...

  5. 数据结构与算法 Javascript描述

    数据结构与算法系列主要记录<数据结构与算法 Javascript描述>学习心得

  6. 读后感:数据结构与算法JavaScript描述

    本书看完,对常见的数据结构与算法从概念上有了更深入的理解. 书中关于数组.栈和队列.链表.字典.散列.集合.二叉树.图.排序.检索.动态规划.贪心算法都有详细的介绍.算是一本不错的学习书籍. 栈和队列 ...

  7. 读《数据结构与算法 Javascript描述》 | 平淡无奇

    “平淡无奇”,一句话总结. 当初买这本书的原因,在意的是有没有什么令人惊喜的东西,特别是针对Javascript代码的奇思妙想,所以就买下了这本书. 在买的几本书里面,最先看的也是这一本,但看起目录就 ...

  8. 数据结构与算法JavaScript描述——使用队列

    1.使用队列:方块舞的舞伴分配问题 前面我们提到过,经常用队列模拟排队的人.下面我们使用队列来模拟跳方块舞的人.当 男男女女来到舞池,他们按照自己的性别排成两队.当舞池中有地方空出来时,选两个队 列中 ...

  9. 数据结构与算法JavaScript描述——链表

    1.数组的缺点 数组不总是组织数据的最佳数据结构,原因如下. 在很多编程语言中,数组的长度是固定的,所以当数组已被数据填满时,再要加入新的元素就会非常困难. 在数组中,添加和删除元素也很麻烦,因为需要 ...

随机推荐

  1. 51单片机引脚ALE/PROG/PSEN/EA/Vpp

    51单片机的4个控制引脚,其中一个引脚是复位引脚(RST/Vpd),RST是复位引脚,当RST输入端保持2个机器周期以上高电平时,就实现复位. ALE/PROG是地址锁存允许信号输出端,在读写外部存储 ...

  2. 如何将Icon转成Bitmap(对ICON的内部格式讲的比较清楚)

    最近工作中有个需求是将Icon转成带Alpha通道的Bitmap, 虽然网上有不少这方面的文章,但很多都是错的, 这里记录下,或许对后来人有用.   要实现这个功能,我们首先需要理解Icon的格式,我 ...

  3. Qt中用QSS切分图片

    Qt设计时有时需要实现动态按钮,按钮点击时一个状态,鼠标悬浮时一个状态,离开时一个状态,静止时一个状态.可以用一张png长图,使用QSS分段截取,分配给每一个状态.    1.调用函数 SetButt ...

  4. Qt在Windows下的三种编程环境搭建

    尊重作者,支持原创,如需转载,请附上原地址:http://blog.csdn.net/libaineu2004/article/details/17363165 从QT官网可以得知其支持的平台.编译器 ...

  5. MySQL常用聚合函数

    官方文档:Aggregate (GROUP BY) Functions Name Description AVG() Return the average value of the argument ...

  6. Smarty 保留变量

    {$smarty} 保留变量 可以通过PHP的保留变量 {$smarty}来访问一些环境变量. 下面是这些变量的列表: 页面请求变量 页面请求变量如$_GET, $_POST, $_COOKIE, $ ...

  7. rnqoj-30- [stupid]愚蠢的矿工-树形DP

    把树转化为二叉树,然后再左右DP: #include<stdio.h> #include<string.h> #include<iostream> #include ...

  8. Resty 一款极简的restful轻量级的web框架

    https://github.com/Dreampie/Resty Resty 一款极简的restful轻量级的web框架 开发文档 如果你还不是很了解restful,或者认为restful只是一种规 ...

  9. 全球扫货指南:面向中国消费者的全球奢侈品旅游导购服务 |PingWest中文网

    全球扫货指南:面向中国消费者的全球奢侈品旅游导购服务 |PingWest中文网 用"全球扫货指南

  10. JDBC中Statement接口提供的execute、executeQuery和executeUpdate之间的区别

    Statement 接口提供了三种执行 SQL 语句的方法:executeQuery.executeUpdate 和 execute.使用哪一个方法由 SQL 语句所产生的内容决定. 方法execut ...