数据结构与算法JavaScript描述 | 数组

1、基础:

数组的标准定义:一个存储元素的线性集合,元素可以通过索引来任意存取,索引通常是数字,用来计算元素之间存储位置的偏移量。

JavaScript 中的数组是一种特殊的对象,用来表示偏移量的索引是该对象的属性,索引可能是属性。然而,这些数字索引在内部被转换为字符串类型,这是因为JS对象中的属性名必须是字符串;即数组在JS中只是特殊的对象。

2、使用数组:

1)创建数组:
① 通过[]操作符声明数组变量:var arr = [];
② 通过[]操作符声明数组变量,同时在[]操作符内放入一组元素:var arr = [1,2,3,4];
③ 通过调用Array的构造函数创建数组:var arr = new Array();
④ 通过调用Array的构造函数创建数组,同时在构造函数中传入一组元素作为数组的初始值:var arr = new Array(1,2,3,4);
⑤ 通过调用Array的构造函数创建数组,同时可以只传入一个参数,来指定数组的长度:var arr = new Array(10);

在脚本语言中,常见的特性——数组中的元素不必是同一种数据类型;
Array.isArray(arrArg); - 用来判断一个对象是否是数组,若是返回true,否则返回false;

2)读写数组:
可以通过[]操作符读写数组中的元素;

3)由字符串生成数组:
调用字符串的split()方法可以将字符串转换为数组;

var sentence = "the quick brown fox jumped over the lazy dog";
var words = sentence.split(' ');
for (var i = 0; i < words.length; i++) {
    console.log('word ' + i + ' : ' + words[i]);
}
/*
输出:
word 0 : the
word 1 : quick
word 2 : brown
word 3 : fox
word 4 : jumped
word 5 : over
word 6 : the
word 7 : lazy
word 8 : dog
*/

4)对数组的整体性操作:
数组浅复制: 修改任意一个都会对另一个造成同样的影响;

var nums = [1, 2, 3, 4, 5, 6, 7];
var newNum = nums;
newNum.push(8);
console.log('nums : ' + nums);
console.log('newNum : ' + newNum);

/*
输出:
 nums : 1,2,3,4,5,6,7,8
 newNum : 1,2,3,4,5,6,7,8
*/

数组深复制:将原数组中的每一个元素都复制一份到新数组中。

function deepCopy(arr) {
    var newObj;
    Object.prototype.toString.call(arr) === '[object Array]'? newObj = []:newObj = {};
    for(var key in arr){
        newObj[key] = (typeof arr[key] === 'object'?deepCopy(arr[key]):arr[key]);
    }
    return newObj;
}

3、存取函数:

1)查找元素:
indexOf()方法:(从左向右查找)用来查找传进来的参数在目标数组中是否存在,如果目标数组包含该参数,就返回该元素在数组中的索引,如果不包含,就返回-1;
lastIndexOf()方法:(从右向左查找)用来查找传进来的参数在目标数组中是否存在,如果目标数组包含该参数,就返回该元素在数组中的索引,如果不包含,就返回-1;

2)数组的字符串表示:
join()方法:将数组转换为字符串;
toString()方法:将数组转换为字符串;

3)由已有数组创建新数组:
concat()方法:允许通过已有数组创建新数组,可以合并多个数组创建一个新数组;
splice()方法:允许通过已有数组创建新数组,截取一个数组的子集创建一个新数组;

4、可变函数:

1)为数组添加元素:
push()方法:会将一个元素添加到数组末尾,可以一次添加多个元素;

也可以使用length属性为数组添加元素,如:num[num.length] = 5;

unshift()方法:可以将元素添加到数组的开头,可以一次添加多个元素;

2)从数组中删除元素:
pop()方法:可以删除数组末尾的元素;
shift()方法:可以删除数组的第一个元素;

3)从数组中间位置添加或删除元素
splice()方法:为数组添加元素,参数如下:

  • 起始索引 - 希望开始添加元素的位置;
  • 需要删除的元素个数(添加元素时该参数设为0);
  • 想要添加进数组的元素;

4)为数组排序
reverse()方法:将数组中的元素的顺序进行翻转(注意:该方法会修改原数组);
sort()方法:对数组进行排序,默认情况下 ,sort方法按字典顺序对元素进行排序,即使元素为数字类型也会被认为是字符串类型(注意:该方法会修改原数组);

  • 参数 - 比较函数
var arr3 = [1,5,2,4,10,8,7];
arr3.sort(function (a,b) {
    return a-b;
});
console.log(arr3); // [ 1, 2, 4, 5, 7, 8, 10 ]

5、 迭代器方法:

1)不生成新数组的迭代器方法:
forEach()方法:该方法接受一个函数作为参数,对数组中的每个元素使用该函数;

var nums = [1,2,3,4,5,6,7,8];
nums.forEach(function (num) {
   console.log(num,num*num);
});

every()方法:该方法接受一个返回值为布尔类型的函数,对数组的每个元素使用该方法,如果对于所有元素,该函数均返回true,则该方法返回true

var arr1 = [1,2,3,4,5,6];
var arr2 = [2,4,6,8,10];
function isEven(num) {
    return num%2;
}
console.log(arr1.every(isEven));
console.log(arr2.every(isEven));

some()方法:该方法接受一个返回值为布尔类型的函数,只要有一个元素使得该函数返回true,该方法就返回true
reduce()方法:(从左向右)接受一个函数,返回一个值;该方法会从一个累加值开始,不断对累加值和数组中的后续元素调用该函数,直到数组中的最后一格元素,最后返回得到的累加值(注意:也可以用来将数组中的元素连接成一个长的字符串);

var sum = arr1.reduce(function (a,b) {
    return a+b;
});
console.log(sum);

reduceRight()方法:(从右向左)接受一个函数,返回一个值;该方法会从一个累加值开始,不断对累加值和数组中的后续元素调用该函数,直到数组中的最后一格元素,最后返回得到的累加值(注意:也可以用来将数组中的元素连接成一个长的字符串);

2)生成新数组的迭代器方法:
map()方法:对数组中的每个元素使用某个函数,并返回一个新的数组,该数组的元素是对原有元素应用某个函数的结果;

var arr3 = [22,45,11,57,38];
function addNum(num) {
    return num += 10;
}
var res = arr3.map(addNum);
console.log(res);

filter()方法:传入一个返回值为布尔类型的函数,当所有元素应用该函数时,返回一个新数组,该数组包含应用该函数后结果为true的元素;

var nums2 = [12, 14, 23, 4, 6];
function isOdd(num) {
    return !(num % 2);
}
console.log(nums2.filter(isOdd)); // [ 12, 14, 4, 6 ]

filter方法的其他应用——筛选数组元素:

var grades = [39,43,89,19,46,54,5,13,31,27,96,64,63,30,78,89,68,40];
function isPass(grade) {
    return (grade >=60);
}
var passGrade = grades.filter(isPass);
console.log('All grades : ');
console.log(grades);
console.log('Passing grades : ');
console.log(passGrade);
/*
输出:
  All grades : 
  [ 39, 43, 89, 19, 46, 54, 5, 13, 31, 27, 96, 64, 63, 30, 78, 89, 68, 40 ]
  Passing grades : 
  [ 89, 96, 64, 63, 78, 89, 68 ]
*/

6、二维和多维数组:

JavaScript中只支持一维数组,但是通过在数组中保存数组元素的方式,可以轻松创建多维数组;

1)创建二维数组:

// JavaScript:The Good Parts
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;
    }
    return arr;
};

var nums = Array.matrix(3,2,'1');
console.log(nums);

2)处理二维数组的元素:
处理二维数组,有两种最基本的方式:按列访问,按行访问;

// 每个学生三科成绩,求平均分:
var grades = [[89, 77, 68], [79, 60, 90], [70, 88, 60]];
for (var i = 0; i < grades.length; i++) {
    var total = 0;
    var average = 0;
    for (var j = 0; j < grades[i].length; j++) {
        total += grades[i][j];
    }
    average = total / grades[i].length;
    console.log('Student ' + i + ' average : ' + average.toFixed(2));
}

// 计算各科的平均成绩
for (var m = 0; m < grades.length; m++) {
    var total = 0;
    var average = 0;
    for (var n = 0; n < grades[m].length; n++) {
        total += grades[n][m];
    }
    average = total / grades.length;
    console.log('Test ' + (m+1) + ' average : ' + average.toFixed(2));
}

7、对象数组:

数组的方法、属性对对象依然适用。


练习:

1、创建一个记录学生成绩的对象,提供一个添加成绩的方法,以及一个现实学生平均成绩的方法:

function StuGrade() {
    this.dataStore = [];
    this.addGrade = addGrade;
    this.showAverage = showAverage;
}
function addGrade(grade) {
    this.dataStore.push(grade);
}
function showAverage() {
    var total = 0;
    for(var i = 0;i

2、将一组单词存储在一个数组中,并按正序和倒叙分别显示这些单词:

使用sortreverse方法即可实现;

3、创建一个对象,用于保存观测到的周最高温度,该对象有多个方法:①增加一条新的气温记录;②计算存储在对象中的平均气温;(扩展:修改创建的对象,使它可以使用一个二维数组来存储每个月的有用数据,增加一些方法用以显示月平均数,具体某一周平均数和所有周的平均数)


function Temperature() {
    this.num = 0;
    this.dataStore = [];
    this.add = function (t) {
        var n = this.num % 7;
        var m = parseInt(this.num / 7);
        if (n == 0) {
            this.dataStore.push([]);
        }
        this.dataStore[m].push(t);
        this.num++;
    };
    this.weekAverage = function (w) {
        var total = 0;
        w = w-1;
        for (var i = 0; i < this.dataStore[w].length; i++) {
            total += this.dataStore[w][i];
        }
        return total / this.dataStore[w].length;
    };
    this.monthAverage = function () {
        var t = 0;
        for(var k =0 ;k

4、创建一个对象,它将字母存储在一个数组中,并且用一个方法可以将字母连在一起,显示成一个单词;

function ConstWord() {
    this.data = [];
    this.add = function (c) {
        this.data.push(c);
    };
    this.connect = function () {
        return this.data.join('');
    };
}

var w = new ConstWord();
w.add('H');
w.add('e');
w.add('l');
w.add('l');
w.add('o');
console.log(w.connect());

相关算法:

1、数组去重:

/*
 * 方法一:
 * 使用indexOf方法去重
 * 优点:可以识别字符串类型的数字和数字类型的数字;
 * 缺点:对于引用类型的数组元素无法判断
 * */
function unique1(arr) {
    var res = [];
    for (var i = 0; i < arr.length; i++) {
        if (res.indexOf(arr[i]) == -1) {
            res.push(arr[i]);
        }
    }
    return res;
}
var arr1 = [1, 2, 1, 6, 3, 7, 2, 4, 9, 5];
console.log(unique1(arr1)); // [ 1, 2, 6, 3, 7, 4, 9, 5 ]

var arr2 = [1, 2, '1', 6, 3];
console.log(unique1(arr2)); // [ 1, 2, '1', 6, 3 ]

var arr3 = [1, 2, '1', 6, 3, [1, 2, 4, 6], [1, 2, 4, 6], 7, 2, 4, 9, 5];
console.log(unique1(arr3)); // [ 1, 2, '1', 6, 3, [ 1, 2, 4, 6 ], [ 1, 2, 4, 6 ], 7, 4, 9, 5 ]

console.log('===============================');
/*
 * 方法二:
 * 利用hash表
 * 优点:对引用类型的数组元素可以判断去重
 * 缺点:对数字类型的字符串无法判断
 *(原因:对象类型的属性名均被转换为字符串类型,不论原本是什么类型)
 * */
function unique2(arr) {
    var hash = {};
    var res = [];
    for (var i = 0; i < arr.length; i++) {
        if (!hash[arr[i]]) {
            hash[arr[i]] = true;
            res.push(arr[i]);
        }
    }
    return res;
}
var arr2_1 = [1, 2, 1, 6, 3, 7, 2, 4, 9, 5];
console.log(unique2(arr2_1)); // [ 1, 2, 6, 3, 7, 4, 9, 5 ]

var arr2_2 = [1, 2, '1', 6, 3];
console.log(unique2(arr2_2)); // [ 1, 2, 6, 3 ]

var arr2_3 = [1, 2, '1', 6, 3, [1, 2, 4, 6], [1, 2, 4, 6], 7, 2, 4, 9, 5];
console.log(unique2(arr2_3)); // [ 1, 2, 6, 3, [ 1, 2, 4, 6 ], 7, 4, 9, 5 ]

console.log('================================');

/*
 * 方法三:
 * 双重遍历
 * 优点:可以识别出字符串类型的数字;
 * 缺点:对引用类型的数组元素无效,且效率略低;
 * */
function unique3(arr) {
    if (arr.length == 0 || arr.length == 1)
        return;
    var res = [arr[0]], isRepeat;
    for (var i = 0; i < arr.length; i++) {
        isRepeat = false;
        for (var j = 0; j < res.length; j++) {
            if(res[i] === arr[j]){
                isRepeat = true;
                break;
            }
        }
        if(!isRepeat){
            res.push(arr[i]);
        }
    }
    return res;
}
var arr3_1 = [1, 2, 1, 6, 3, 7, 2, 4, 9, 5];
console.log(unique3(arr3_1)); // [ 1, 2, 6, 3, 7, 4, 9, 5 ]

var arr3_2 = [1, 2, '1', 6, 3];
console.log(unique3(arr3_2)); // [ 1, 2, '1', 6, 3 ]

var arr3_3 = [1, 2, '1', 6, 3, [1, 2, 4, 6], [1, 2, 4, 6], 7, 2, 4, 9, 5];
console.log(unique3(arr3_3)); // [ 1, 2, '1', 6, 3, [ 1, 2, 4, 6 ], [ 1, 2, 4, 6 ], 7, 2, 4, 9, 5 ]

2、数组乱序:

// 方法一:
// 使用random方法获取随即元素添加到res中
// 同时使用delete删除array中对应的元素
function shuffle1(array) {
    var res = [];
    var i = 0;
    var n = array.length;
    while(n){
        i = Math.floor(Math.random()*array.length);
        if(i in array){
            res.push(array[i]);
            delete array[i];
            n--;
        }
    }
    return res;
}
var nums = [1,2,3,4,5,6];
console.log(shuffle1(nums));

// 方法二:
// 与方法一类似,只是是使用splice方法移除array中的元素
function shuffle2(array) {
    var res = [];
    var n = array.length;
    var i = 0;
    while (n) {
        i = Math.floor(Math.random() * array.length);
        if (i in array) {
            res.push(array.splice(i, 1)[0]);
            n--;
        }
    }
    return res;
}
var nums2 = [1, 2, 3, 4, 5, 6];
console.log(shuffle2(nums2));


// 方法三:
// 前面随机抽取一个数值与末尾的元素交换,后面依次类推;
function shuffle3(array) {
    var n = array.length;
    var i = 0;
    while(n){
        i = Math.floor(Math.random()*n--);
        t = array[n];
        array[n] = array[i];
        array[i] = t;
    }
    return array;
}
var nums3 = [1, 2, 3, 4, 5, 6];
console.log(shuffle3(nums3));

3、数组求交集:

Array.prototype.intersection = function (arr) {
   return this.filter(function (n) {
        return arr.indexOf(n) != -1;
    })
};

var arr1 = [1,4,2,6,9,5];
var arr2 = [1,5,2,5,0,3];
var res = arr1.intersection(arr2);
console.log(res); // [ 1 , 2 , 5 ]

4、数组求并集:

// 思路一:将两个数组连接在一起再去重
Array.prototype.unionSet = function (arr) {
    var res = this.concat(arr);
    return unique(res);
};

function unique(arr) {
    var res = [];
    for (var i = 0; i < arr.length; i++) {
        if (res.indexOf(arr[i]) == -1) {
            res.push(arr[i]);
        }
    }
    return res;
}

var arr1 = [1, 4, 2, 6, 9, 5, 1];
var arr2 = [1, 5, 2, 5, 0, 3];
var res = arr1.unionSet(arr2);
console.log(res);

// 思路二:求两个数组的交集、两个数组的差集(A-B及B-A),再将三个数组连接在一起

5、数组求差集:

Array.prototype.differenceSet = function (arr) {
    return this.filter(function (n) {
        return arr.indexOf(n) == -1;
    })
};

var arr1 = [1, 4, 2, 6, 9, 5, 1];
var arr2 = [1, 5, 2, 5, 0, 3];

var one_two = arr1.differenceSet(arr2);
var two_one = arr2.differenceSet(arr1);

console.log('arr1-arr2: '+one_two);
console.log('arr2-arr1: '+two_one);

6、数组判断:

// 方法一:自带的isArray方法
var nums = [1,2,3];
console.log(Array.isArray(nums)); // true

// 方法二:利用instanceof 运算符判断
var arr = ['2','1','5'];
console.log(arr instanceof Array); // true

// 方法三:利用toString判断
var str = ['h','e','l','l','o'];
console.log(Object.prototype.toString.call(str) == '[object Array]'); // true

补充:

1、Math 对象

Math 对象:保存数学公式和信息提供了一个公共位置;

1)Math 对象的属性:

  • Math.E - 自然对数的底数,即常量e的值;
  • Math.LN10 - 10的自然对数;
  • Marh.LN2 - 2的自然对数;
  • Marh.LOG2E - 以2为底e的对数;
  • Marh.LOG10E - 以10为底e的对数;
  • Marh.PI - π的值;
  • Marh.SQRT1_2 - 1/2的平方根,即2的平方根的倒数;
  • Marh.SQRT2 - 2的平方根;

2)min()和max()方法:

这两个方法都可以接收任意多个数值参数;

min()方法:确定一组数值中的最小值;
max()方法:确定一组数值中的最大值;

// 要找到数组中的最大或最小值:
var nums = [1,2,3,2,7,5,9];
var max = Math.max.apply(Math,nums); // 9
var min = Math.min.apply(Math,nums); // 1

3)舍入方法:

  • Math.ceil()方法:执行向上舍入;
  • Math.floor()方法:执行向下舍入;
  • Math.round()方法:执行标准舍入(即四舍五入);

4)random()方法:
Math.random()方法:返回大于等于0小于1的随机数,即[0,1);

从某个整数范围内随即选择一个值:
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)

// 返回指定范围内的一个随即数
function selectFrom(lowerValue , upperValue){
    var choice = upperValue - lowerValue;
    return Math.floor(Math.random() * choice + lowerValue);
}

5)其他方法:

  • Math.abs(num)方法:返回num的绝对值
  • Math.exp(num)方法:返回Math.E的num次幂
  • Math.log(num)方法:返回num的自然对数
  • Math.pow(num, power)方法:返回num的power次幂
  • Math.sqrt(num)方法:返回num的平方根
  • Math.acos(x)方法:返回x的反余弦值
  • Math.asin(x)方法:返回x的反正弦值
  • Math.atan(x)方法:返回x的反正切值
  • Math.atan2(y, x)方法:返回y/x的反正切值
  • Math.cos(x)方法:返回x的余弦值
  • Math.sin(x)方法:返回x的正弦值
  • Math.tan(x)方法:返回x的正切值

2、delete 关键字:

delete 只有当一个属性无法被删除时才返回 false,若删除成功则返回true;



作者:Indinity
链接:http://www.jianshu.com/p/405ecb84c4f8
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(javascript,设计模式,前端性能优化,数据结构,算法,脚本语言,对象,索引)