javaScript中关于数组的十八般武艺(一)

304 阅读7分钟

什么是数组

数组对象是使用单独的变量名来存储一系列的值。数组可以用一个变量名存储所有的值,并且可以用变量名访问任何一个值。数组中的每个元素都有自己的的ID,

创建一个数组

  • 常规方式:
var citys=new Array();
citys[0]="beijing";      
citys[1]="shanghai";
citys[2]="wuhan";
console.log(citys[0]); //beijing
  • 简洁方式:
var citys=new Array("beijing","shanghai","wuhan");
console.log(citys[1]); //shanghai
  • 字面:
var citys=["beijing","shanghai","wuhan"];
console.log(citys[2]); //wuhan
  • Array.from() 方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
var arr = Array.from('shenzhen');
console.log(arr); // ["s", "h", "e", "n", "z", "h", "e", "n"]

数组排序

  • sort()方法
var array = [1,4,-8,-3,6,12,9,8];
function compare(val1,val2){
    return val1-val2;
};
array.sort(compare);
  • 反转数组reverse()
var citys=new Array("beijing","shanghai","wuhan");
console.log(citys); // ["beijing", "shanghai", "wuhan"]
citys.reverse();
console.log(citys);  // ["wuhan", "shanghai", "beijing"]
  • 冒泡排序
    1、比较相邻的两个元素,如果前一个比后一个大,则交换位置。
    2、比较完第一轮的时候,最后一个元素是最大的元素。
    3、这时候最后一个元素是最大的,所以最后一个元素就不需要参与比较大小。
function bubbleSort(arr) {
  var len = arr.length;
  for (var i = 0; i < len-1; i++) {
    for (var j = 0; j < len - 1 - i; j++) {
        // 相邻元素两两对比,元素交换,大的元素交换到后面
       if (arr[j] > arr[j + 1]) {
            var temp = arr[j];
            arr[j] = arr[j+1];
            arr[j+1] = temp;
        }
    }
  }
  return arr;
}
//举个数组
myArr = [1, 28, 32, -9, 22];
//使用函数
bubbleSort(myArr)  //[-9, 1, 22, 28, 32]
  • 选择排序
    1、算法简介序
    选择排序是一个简单直观的排序方法,它的工作原理很简单,首先从未排序序列中找到最大的元素,放到已排序序列的末尾,重复上述步骤,直到所有元素排序完毕。
    2、算法描述
    1)假设未排序序列的第一个是最大值,记下该元素的位置,从前往后比较
    2)若某个元素比该元素大,覆盖之前的位置
    3)重复第二个步骤,直到找到未排序的末尾
    4)将未排序元素的第一个元素和最大元素交换位置
    5)重复前面几个步骤,直到所有元素都已经排序。
    3、算法分析
    选择排序的交换操作次数最好情况已经有序为0次,最坏情况逆序n-1次,因此交换操作次数位于0~(n-1)次之间;比较操作次数(n-1+…+2+1+0)为n(n-1)/2次;交换元素赋值操作为3次,逆序需要n-1趟交换,因此,赋值操作位于0~3(n-1)次之间。由于需要交换位置,所以肯定是不稳定的。
function selsetSort(arr){
	var len = arr.length;
	var index;
	for(var i=0;i<len-1;i++){
		index=i;
		for(var j=i+1;j<len;j++){
			if(arr[index]>arr[j]){//寻找最小值
				index=j;//保存最小值的索引
			}
		}
		if(index!=i){
		var temp =arr[i];
		arr[i]=arr[index];
		arr[index]=temp;
	}
	}
	return arr;
}
myArr =[5,3,6,7,9,1,23,32,11,8];
//使用函数
selsetSort(myArr) // [1, 3, 5, 6, 7, 8, 9, 11, 23, 32]
  • 快速排序
    数组中指定一个元素作为标尺,比它大的放到该元素后面,比它小的放到该元素前面,如此重复直至全部正序排列。
    1、选基准:在数据结构中选择一个元素作为基准(pivot)
    2、划分区:参照基准元素值的大小,划分无序区,所有小于基准元素的数据放入一个区间,所有大于基准元素的数据放入另一区间,分区操作结束后,基准元素所处的位置就是最终排序后它应该所处的位置
    3、递归:对初次划分出来的两个无序区间,递归调用第 1步和第 2步的算法,直到所有无序区间都只剩下一个元素为止。
function quickSort(arr) {
    arr = arr.concat();
    if(arr.length<=1){
        return arr
    }
    let left=[], right=[];
     let basis = arr.splice(0,1);
    arr.forEach(function (v) {
        if(v<basis){
            left.push(v)
        }else{
            right.push(v)
        }
    });
    return quickSort(left).concat(basis,quickSort(right))
}
myArr = [1, 28, 32, -9, 22,48,-7848,77];
//使用函数
quickSort(myArr) // [-7848, -9, 1, 22, 28, 32, 48, 77]
  • 插入排序
    1,算法简介
    插入排序的工作原理就是将未排序数据,对已排序数据序列从后向前扫描,找到对应的位置并插入。插入排序通常采用占位的形式,空间复杂度为O(1),因此,在从后向前扫描的过程中,需要反复的把已排序的元素逐步向后挪位,为新插入元素提供插入的位置。

    2,算法描述
    1)从第一个元素开始,该元素可以被认为已经被排序
    2)取出下一个元素,在已经排好序的序列中从后往前扫描
    3)直到找到小于或者等于该元素的位置
    4)将该位置后面的所有已排序的元素从后往前依次移一位
    5)将该元素插入到该位置
    6)重复步骤2~5
function insertSort(arr){
    var len = arr.length
    for(var i=1;i<len;i++){
        var temp = arr[i]
        var j = i-1
        while(arr[j]>temp){
            arr[j+1]=arr[j]
            j--
        }
        arr[j+1]=temp
    }
    return arr
}
var myArr = [5,3,2,7,8]
insertSort(myArr) //[2,3,5,7,8]
  • 希尔排序
    希尔(Shell)排序又称为缩小增量排序,它是一种插入排序。它是直接插入排序算法的一种威力加强版。
    希尔排序的基本思想是:
    把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。、随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到1时,整个数据合成为一组,构成一组有序记录,则完成排序。

function shellSort(array) {
    let gap = Math.floor(array.length / 2);
    while (1 <= gap) {
        // 把距离为 gap 的元素编为一个组,扫描所有组
        for (let i = gap; i < array.length; i++) {
            let j = 0;
            let temp = array[i];
            // 对距离为 gap 的元素组进行排序
            for (j = i - gap; j >= 0 && temp < array[j]; j -= gap) {
                array[j + gap] = array[j];
            }
            array[j + gap] = temp;
        }
        gap = Math.floor(gap / 2); // 减小增量
    }
    return array;
}

let arr = [98, 42, 25, 54, 15, 3, 25, 72, 41, 10, 121];
shellSort(arr);  //[3, 10, 15, 25, 25, 41, 42, 54, 72, 98, 121]
  • 归并排序
    1、基本思想与过程:先递归的分解数列,再合并数列(分治思想的典型应用)
      (1)将一个数组拆成A、B两个小组,两个小组继续拆,直到每个小组只有一个元素为止。
      (2)按照拆分过程逐步合并小组,由于各小组初始只有一个元素,可以看做小组内部是有序的,合并小组可以被看做是合并两个有序数组的过程。
      (3)对左右两个小数列重复第二步,直至各区间只有1个数。
      下面对数组【42,20,17,13,28,14,23,15】进行归并排序,模拟排序过程如下:
      第一步:拆分数组,一共需要拆分三次(logN);
        第一次拆成【42,20,17,13】,【28,14,23,15】,
        第二次拆成【42,20】,【17,13】,【28,14】,【23,15】,、
        第三次拆成【42】,【20】,【17】,【13】,【28】,【14】,【23】,【15】;
      第二步:逐步归并数组,采用合并两个有序数组的方法,每一步其算法复杂度基本接近于O(N)
        第一次归并为【20,42】,【13,17】,【14,28】,【15,23】
        第二次归并为【13,17,20,42】,【14,15,23,28】,
        第三次归并为【13, 14, 15, 17, 20, 23, 28, 42】
function merge(left, right) {
  var tmp = [];
  while (left.length && right.length) {
    if (left[0] < right[0])
      tmp.push(left.shift());
    else
      tmp.push(right.shift());
  }
  return tmp.concat(left, right);
}
 
function mergeSort(a) {
  if (a.length === 1) 
    return a;
  var mid = Math.floor(a.length / 2);
  var left = a.slice(0, mid);
  var right = a.slice(mid);
  return merge(mergeSort(left), mergeSort(right));
}
var arr = [42,20,17,13,28,14,23,15]; //[13, 14, 15, 17, 20, 23, 28, 42]

比较

排序算法 平均情况 最好情况 最坏情况 稳定性
冒泡排序 O(n²) O(n) O(n²) 稳定
选择排序 O(n²) O(n²) O(n²) 不稳定
插入排序 O(n²) O(n) O(n²) 稳定
希尔排序 O(nlogn)~O(n²) O(n^1.5) O(n²) 不稳定
归并排序 O(nlogn) O(nlogn) O(nlogn) 稳定
快速排序 O(nlogn) O(nlogn) O(n²) 不稳定