一、定义
往有序的数组中插入一个新元素。
二、算法思想
把要排序的数组分为了两个部分,一部分是数组的全部元素(除去待插入的元素),另一部分是待插入的元素;
先将第一部分排序完成,然后再插入这个元素。其中第一部分的排序也是通过再次拆分为两部分来进行的。
三、具体实现
1、直接插入排序
将待排序的元素按照大小顺序,依次插入到一个已经排好序的数组之中,直到所有的元素都插入进去。
由于直接插入排序每次只移动一个元素的位置,并不会改变值相同的元素之间的排序,因此它是一种稳定排序。
function insertSort(arr) { var len = arr.length, // 数组的长度 current, // 当前比较的值 i, // 未排序部分的当前位置 j; // 已排序部分的当前位置 for(i=0; i < len; i++) { // 储存当前位置的值 current = arr[i]; /* * 当已排序部分的当前元素大于current, * 就将当前元素向后移一位,再将前一位与current比较。 */ for(j=i-1; j > -1 && arr[j] > current; j--) { arr[j+1] = arr[j]; } arr[j+1] = current; } return arr; } console.log(insertSort([3,115,9,2,11,6,3,19]));
2、折半插入排序
比较中间值与待插入元素的大小,折半插入排序每次交换的是相邻的且值为不同的元素,它并不会改变值相同的元素之间的顺序,因此它是稳定的。明显减少了查询的次数,但是数组元素移动的次数却没有改变。
function binaryInsertSort(arr){ var current, i, j, low, high, mid; for(i = 1; i < arr.length; i++){ low = 0; high = i - 1; current = arr[i]; while(low <= high){ //步骤1&2:折半查找 mid = (low + high)>>1; if(current >= arr[mid]){//值相同时, 切换到高半区,保证稳定性 low = mid + 1; //插入点在高半区 }else{ high = mid - 1; //插入点在低半区 } } for(j = i; j > low; j--){ //步骤3:插入位置之后的元素全部后移一位 arr[j] = arr[j-1]; } arr[low] = current; //步骤4:插入该元素 } return arr; } console.log(binaryInsertSort([3,115,9,2,11,6,3,19]));
3、希尔排序
缩小增量排序,实质就是分组插入排序。先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
单次直接插入排序是稳定的,它不会改变相同元素之间的相对顺序,但在多次不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,可能导致相同元素相对顺序发生变化。因此,希尔排序并不稳定。
function shellSort(arr) { let len = arr.length, current, gap = 1; while(gap < len / 3) { gap = gap * 3 + 1; } for(gap; gap > 0; gap = Math.floor(gap / 3)) { for(let i = gap; i < len; i++) { current = arr[i]; for (var j = i - gap; j >= 0 && arr[j] > current; j -= gap) { arr[j + gap] = arr[j]; } if(j + gap !=i){ arr[j + gap] = current; } } } return arr; } console.log(shellSort([3,115,9,2,11,6,3,19]));
四、效率分析
1、时间复杂度
最坏的情况:时间复杂度为O(n²);
最佳的情况:时间复杂度为O(n²);
平均来讲,时间复杂度为O(n²)。
2、空间复杂度
空间复杂度为常量O(1)。
时间: 2024-10-29 03:48:17