学习来源:https://www.bilibili.com/video/BV1HJ41147DG
1、概念
- 数组可以把一组相关的数据一起存放,并提供方便的访问(获取)方式。
- 数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。
2、创建数组
JS 中创建数组有两种方式:
利用 new 创建数组
var 数组名 = new Array() ; /* 注意 Array () ,A 要大写 */
// 例如
var arr = new Array(); // 创建一个新的空数组
利用数组字面量创建数组
// 1. 使用数组字面量方式创建空的数组
var 数组名 = [];
// 2. 使用数组字面量方式创建带初始值的数组
var 数组名 = ['小白','小黑','大黄','瑞奇'];
- 数组里的数据用逗号分隔
- 数组的字面量是方括号 [ ]
- 声明数组并赋值称为数组的初始化
- 这种字面量方式也是我们以后最多使用的方式
- 数组元素的类型
- 数组中可以存放任意类型的数据,例如字符串,数字,布尔值等。
var arrStus = ['小白',12,true,28.9];
3、获取数组中的元素
- 索引 (下标) :用来访问数组元素的序号(数组下标从 0 开始)。
- 数组可以通过索引来访问、设置、修改对应的数组元素,可以通过“数组名[索引]”的形式来获取数组中的元素。
// 定义数组
var arrStus = [1,2,3];
// 获取数组中的第2个元素
alert(arrStus[1]);
注意
- 如果访问时数组没有和索引值对应的元素,则得到的值是undefined
4、遍历数组
-
数组遍历
把数组中的每个元素从头到尾都访问一次(类似学生的点名),可以通过 for 循环索引遍历数组中的每一项
var arr = ['red','green', 'blue'];
for(var i = 0; i < arr.length; i++){
console.log(arrStus[i]);
}
-
数组的长度
数组的长度:默认情况下表示数组中元素的个数
使用“数组名.length”可以访问数组元素的数量(数组长度)
var arrStus = [1,2,3]; alert(arrStus.length); // outputs “3”
注意
- 此处数组的长度是数组元素的个数 ,不要和数组的索引号混淆。
- arr.length动态监测数组元素的个数
- 当我们数组里面的元素个数发生了变化,这个 length 属性跟着一起变化
- 数组的length属性可以被修改
- 如果设置的length属性值大于数组的元素个数,则会在数组末尾出现空白元素
- 如果设置的length属性值小于数组的元素个数,则会把超过该值的数组元素删除
示例
1、将数组 [‘red’, ‘green’, ‘blue’, ‘pink’] 转换为字符串,并用符号 | 分割
思路:
- 1、需要一个新变量用于存放转换完的字符串 str
- 2、遍历原来的数组,分别把里面数据取出来,加到字符串里面。
- 3、同时在后面多加一个分隔符
<script>
var arr = ['red', 'green', 'blue', 'pink'];
var str = '';
for (var i = 0; i < arr.length; i++) {
str += arr[i] + '|';
}
console.log(str);
</script>
2、将数组 [‘red’, ‘green’, ‘blue’, ‘pink’] 转换为字符串,并用其他符号分割
<script>
var arr = ['red', 'green', 'blue', 'pink'];
var str = '';
var sep = '*'; // 方便修改
for (var i = 0; i < arr.length; i++) {
str += arr[i] + sep;
}
console.log(str);
</script>
5、数组中新增元素
修改length长度
- 可以通过修改 length长度来实现数组扩容的目的
- length 属性是可读写的
<script>
var arr = ['red', 'green', 'blue', 'pink'];
arr.length = 7;
console.log(arr);
console.log(arr[4]);
console.log(arr[5]);
console.log(arr[6]);
</script>
其中索引号是4, 5 , 6的空间没有给值,就是声明变量未给值,默认值就是undefined
修改数组索引
- 可以通过修改数组索引的方式追加数组元素
- 不能直接给数组名赋值 ,否则会覆盖掉以前的数据
<script>
var arr = ['red', 'green', 'blue', 'pink'];
arr[4] = 'pink1';
console.log(arr);
arr[5] = 'red1';
console.log(arr);
/* 替换数组元素 */
arr[2] = 'blue1';
console.log(arr);
/* 不能直接给数组名赋值 ,否则以前的数据就都没有了,完全覆盖掉以前的数据 */
arr = 'yellow';
console.log(arr);
</script>
这种方式也是我们最常用的一种方式
在数组的末尾插入新元素
数组[ 数组.length ] = 新数据;
6、数组案例
案例1:删除某个数后形成新数组
- 将数组[2, 0, 6, 1, 77, 0, 52, 0, 25, 7]中的 0 去掉后,形成一个不包含 0 的新数组
思路
- 需要一个新数组用于存放筛选之后的数据
- 遍历原来的数组, 把不是0的数据添加到新数组里面(此时要注意采用数组名 + 索引的格式接收数据)
- 新数组里面的个数, 用 length 不断累加
<script>
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] != 0) {
newArr[newArr.length] = arr[i];
}
}
console.log(newArr);
</script>
案例2:数组冒泡排序
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
例如:我们可以将数组[3,4,1,5,2]中的元素按照从大到小的顺序排序,输出:5,4,3,2,1
参考:https://www.cnblogs.com/jyroy/p/11248691.html
- 常规方法
// 将数组[6,7,5,4,3,2,1]按从大到小排序
<script>
var arr = [6,7,5,4,3,2,1];
for (var i = 0; i < arr.length - 1; i++) { // 外层循环管趟数
for (var j = 0; j < arr.length - i - 1; j++) { // 里面的循环管 每一趟的交换次数
// 内部交换2个变量的值 前一个和后面一个数组元素相比较
if (arr[j] < arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
console.log('第' + (i + 1) + '遍的第' + (j + 1) + '次交换:' + arr);
}
console.log('第' + (i + 1) + '遍的最终结果:' + arr);
console.log('########');
}
console.log('最终结果:' + arr);
</script>
可以发现从第2遍的交换之后的比较与交换是多余的。
- 第一次优化
- 我们可以针对常规方法的问题做一次优化,即减少多余比较、交换
- 设置一个标志,用来表示当前第 i 趟是否有交换,如果有,就继续进行第 i+1 趟;如果没有,则表示数组已经完成排序,不需要再进行下去了。
<script>
var arr = [6,7,5,4,3,2,1];
for (var i = 0; i < arr.length - 1; i++) { // 外层循环管趟数
var flag = 1; // 标志
for (var j = 0; j < arr.length - i - 1; j++) { // 里面的循环管 每一趟的交换次数
// 内部交换2个变量的值 前一个和后面一个数组元素相比较
if (arr[j] < arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = 0;//发生交换,标志flag=0
}
console.log('第' + (i + 1) + '遍的第' + (j + 1) + '次交换:' + arr);
}
console.log('第' + (i + 1) + '遍的最终结果:' + arr);
console.log('########');
// 如果此趟没有交换元素,表示排序完成
if ( flag == 1 ) {
break;
}
}
console.log('最终结果:' + arr);
</script>
可以发现相比常规方法,第一次优化后少了四遍循环,优化效果显著。
- 第二次优化
- 经过第一次优化后,我们又发现了新的问题,就是内部循环有可能存在多余的比较、交换操作。
- 设置一个标志,用来记录当前第i趟所交换的最后一个位置的下标,在进行第 i+1 趟的时候,只需要内循环到这个下标的位置就可以了,因为后面位置上的元素在上一趟中没有换位,这一次也不可能会换位置了。
<script>
var arr = [6,7,5,4,3,2,1];
var len = arr.length - 1;
var status = 0;//记录最后一次交换的位置
for (var i = 0; i < arr.length - 1; i++) { // 外层循环管趟数
var flag = 1; // 标志
for (var j = 0; j < len; j++) { // 里面的循环管 每一趟的交换次数
// 内部交换2个变量的值 前一个和后面一个数组元素相比较
if (arr[j] < arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = 0;//发生交换,标志flag=0
status = j;//记录位置
}
console.log('第' + (i + 1) + '遍的第' + (j + 1) + '次交换:' + arr);
}
len = status;//把最后一次交换的位置给len,来缩减内循环的次数
console.log('第' + (i + 1) + '遍的最终结果:' + arr);
console.log('########');
// 如果此趟没有交换元素,表示排序完成
if (flag == 1) {
break;
}
}
console.log('最终结果:' + arr);
</script>
- 解释
第二次循环条件是 j < arr.Length - 1 - i 的原因- 在上一次循环的时候就已经对于 arr.Length - 1 - i 之前的位数进行排序过,所以不用再进行无用的循环了。
综上所述:冒泡排序性能
算法 | 最好时间 | 最坏时间 | 平均时间 | 额外空间 | 稳定性 |
---|---|---|---|---|---|
冒泡 | O(n) | O(n^2) | O(n^2) | 1 | 稳定 |