冒泡排序
遍历数组,比当前元素小时交换位置,当遇到本轮中的最大元素之后,后面的交换就不会变化
每次循环就能得到本轮循环中的最大元素
function findMAx(arr) {
var n = arr.length - 1;
//设置flg标记 序列是否有序
//只要序列有序 flag等于上一个循环的flag=true,不会进入if语句,那么flag=false,退出for循环
for (var flag = false; flag = !flag; n--) {
for (var i = 1; i <= n; i++) {
if (arr[i - 1] > arr[i]) {
//交换
console.log(arr[i-1],arr[i]);
//js中数组存储是引用类型
swap(arr,i - 1, i);
flag = false;
}
}
}
return arr;
}
function swap(arr,i, j) {
var t = arr[i];
arr[i]=arr[j];
arr[j]=t;
}
var arr = [1, 3, 4, 2, 1, 4, 6];
findMAx(arr);
console.log(arr);
选择排序
每次选择数组中最小的元素,放在已排序的内容的后面,继续遍历后面的内容。
function select(arr){
if(!arr) return;
for(var i=0;i<arr.length;i++){
//将当前遍历到的元素作为最小值,在遍历数组后续元素的时候,遇到更小的元素,交换位置
var min=arr[i];
for(var j=i;j<arr.length;j++){
if(arr[j]<min){
swap(arr,i,j);
min=j;
}
}
}
return arr;
}
快速排序:
找到一个基准值pivot
,在[lo,hi]
之间找到它的合适位置
- 小于该基准值
[lo,pivot-1]
- 等于该基准值
pivot
- 大于该基准值
[pivot+1,hi]
一般取 pivot为lo
function quickSort(arr,lo,hi){
if(hi<=lo) return;
//两指针分别从数组的两端进行遍历
var partition=sort(arr,lo,hi);
quickSort(arr,lo,partition-1);
quickSort(arr,partition+1,hi);
}
function sort(arr,lo,hi){
var v=arr[lo];
var i=lo,j=hi+1;
if(!arr) return;
while(true){
//定义两个执政 i左指针从左向右扫描
while(arr[++i]<v) if(i==hi) break;
//右指针从右向左执行
while(arr[--j]>v) if(j==lo) break;
// 当两个指针相遇
if(i>=j) break;
//左指针大于v 右指针小于v交换两个的位置 使得 v左端的值小于等于v v右端的值大于等于v
swap(arr,i,j);
}
//最终找到基准值的合适位置
swap(arr,lo,j);
//返回找到的位置
return j;
}
function sortEnd(arr){
quickSort(arr,0,arr.length-1);
return arr;
}
sortEnd(arr);
console.log(arr);
插入排序
将当前的元素,放到当前遍历区间的合适位置
比如:
当前遍历到a[i]
遍历a[i-1] a[i-2] …a[0] 将a[i]根绝大小放到合适的位置
//插入排序
function insertSort(arr){
if(!arr) return;
for(var i=1;i<=arr.length-1;i++){
for(var j=i;j>=0;j--){
if(arr[j]<arr[j-1]){
swap(arr,j,j-1);
}
}
}
return arr;
}
insertSort(arr);
console.log(arr);
堆排序:
先构造堆,使堆有序,在构造大顶堆
堆有序
:一个二叉树的节点大于等于它的子节点
当前节点k
,父节点
为k/2向下取整
,两个子节点
2*k
和2*k+1
(是从1开始算到N)
但是数组中,一般是从下标为0的索引开始
某个节点比它的父节点大,上浮调整优先级
节点比子节点中较大者小,需要下沉调整位置
function sink(arr, k, N) {
//节点k下沉
while (2 * k + 1 <= N) {
var j = 2 * k+1;
if (j < N && arr[j] < arr[j + 1]) j++;
if (arr[k] >arr[j]) break;
swap(arr, k, j);
k = j;
}
}
//堆排序
function heapSort(arr) {
var N = arr.length - 1;
//堆有序
for (var i = parseInt(N / 2); i >= 0; i--) {
sink(arr, i, N);
console.log(arr);
}
//将堆顶元素和最后的元素交换位置 将数组的范围缩小1(堆顶元素是最大的)
while (N > 0) {
swap(arr, 0, N--);
sink(arr, 0, N);
}
return arr;
}
console.log(heapSort(arr));
归并排序
原地归并排序:将mid左右两端的区间[lo,mid]和[mid+1,hi]排列成有序
自顶向下
使用递归,将数组区间不断的划分成更小的区间,直到该区间有序自底向上
使用循环迭代,将数组的区间以2个宽度开始原地归并排序,循环迭代2倍增长遍历区间的长度
将数组复制一份,数组的区间[lo,mid]
和[mid+1,hi]
是有序的,需要然和并之后的数组也是有序,使用自底向上的归并排序或自顶向下的排序
//原地归并
function merge(arr,lo,mid,hi){
var i=lo,j=mid+1;
//只复制一层就可以了
var arrx=arr.slice(0);
// console.log(arrx);
for(var k=lo;k<=hi;k++){
//当左边元素用完
if(i>mid){
arr[k]=arrx[j++] ;
// console.log('左边:'+arr,arrx);
}
//右边元素用完
else if(j>hi) {
arr[k]=arrx[i++];
// console.log('右边:'+arr,arrx);
}
//当右边 比 左边大 将小值 复制到左边
else if(arrx[i]>arrx[j]) {
arr[k]=arrx[j++];
// console.log('小:'+arr,arrx);
}
//当左边大是 将大值 复制到右边
else {
arr[k]=arrx[i++];
// console.log('大:'+arr,arrx);
}
}
return arr;
}
- 自顶向下归并排序
//自顶向下使用递归,将数组划分成不重叠的子问题
function fromTtB(arr){
sort(arr,0,arr.length-1);
return arr;
}
function sort(arr,lo,hi){
//递归基
if(hi<=lo) return;
var mid=lo+parseInt((hi-li)/2);
sort(arr,lo,mid);
sort(arr,mid+1,hi);
merge(arr,lo,mid,hi);
}
- 自底向上归并排序
function fromBtT(arr){
var N=arr.length;
//sz表示区间的长度
for(var sz=1;sz<N;sz+=sz){
for(var lo=0;lo<N-sz;lo+=sz+sz){
//原地归并 当循环到最后时 ,区间的宽度可能比2sz短,因此区最终剩余的宽度
merge(arr,lo,lo+sz-1,Math.min(lo+sz+sz-1,N-1));
}
}
return arr;
}