js排序和查找算法

一、排序

1. 冒泡
(1)概念:冒泡排序只会比较两个相邻的数据,看是否满足大小关系要求。如果不满足就互换。一次遍历会让至少一个数据 移动到该有的位子。重复N次完成排序。
(2)特点:
时间复杂度O(n2),最好情况时间复杂度O(n),最坏情况时间复杂度O(n2),平均时间复杂度O(n2)。
空间复杂度O(1),也叫原地排序。
稳定性-稳定。
(3)代码:

function bubbleSort(arr){
    for(let i=0;i<arr.length;i++){
        for(let j=0;j<arr.length-i-1;j++){
            if(arr[j]>arr[j+1]){
                [arr[j],arr[j+1]]=[arr[j+1],arr[j]];
            }
        }
    }
}

2. 插入排序
(1)概念:将数组的数据分为两个区间,已排序区间和为排序区间。初始已排序区间有一个元素(数组的第一个元素)。核心思想取未排序区间中的第一个元素,在已排序区间中找到合适的插入位子将其插入,并保证已排序区间数据一致有序。重复N次,完成排序。
(2)特点:
时间复杂度:O(n2),最好情况时间复杂度O(n),最坏情况时间复杂度O(n2),平均时间复杂度O(n2)。
空间复杂度O(1),也叫原地排序。
稳定性-稳定。
(3)代码:

function insertSort(arr){
    for(let i=1;i<arr.length;i++){
        let temp=arr[i];
        let j=i-1;
        //如果有序的序列中比当前这个值大,则进行向后移位
        for(;j>=0 && arr[j]>temp;j--){
            arr[j+1]=arr[j]
        }
        arr[j+1]=temp;//插入值
    }
    return arr;
}

3. 选择排序
(1)概念:将数组的数据分为两个区间,已排序区间和为排序区间。初始已排序区间有一个元素(数组的第一个元素)。核心思想取未排序区间中的最小一个元素,将其放到已排序区间的末尾。重复N次,完成排序。
(2)特点:
时间复杂度:O(n2),最好情况时间复杂度O(n2),最坏情况时间复杂度O(n2),平均时间复杂度O(n2)。
空间复杂度O(1),也叫原地排序。
稳定性-不稳定。
(3)代码:

function selectSort(arr){
    for(let i=0;i<arr.length;i++){
        let minIndex=i;
        //在未排序的序列里找到最小的值的索引
        for(let j=i+1;j<arr.length;j++){
            if(arr[j]<arr[minIndex]){
                minIndex=j;
            }
        }
        [arr[i],arr[minIndex]]=[arr[minIndex],arr[i]];
    }
    return arr
}

三种排序插入排序最受欢迎,原因,选择排序不稳定。冒泡排序需要交换数据。而插入排序只需要移位,代码比冒泡少。
4. 归并排序
(1)概念:把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排序好的两部分合并在一起。

归并排序

(2)特点:
分治思想,用到递归。分治是一种解决问题的处理思想,递归是一种编程技巧。
时间复杂度:O(nlogn),最好情况时间复杂度O(nlogn),最坏情况时间复杂度O(nlogn),平均时间复杂度O(nlogn)。
空间复杂度O(n)。
稳定性-稳定。
(3)代码:

function mergeSort(arr){
    if(arr.length<=1){
        return arr;
    }
    let middleIndex=Math.floor(arr.length/2);
    let leftArr=arr.slice(0,middleIndex);
    let rightArr=arr.slice(middleIndex);
    return merge(mergeSort(leftArr),mergeSort(rightArr));//分治思想
}
function merge(leftArr,rightArr){
    let arr=[];
    while(leftArr.length>0 && rightArr.length>0){
        if(leftArr[0]<rightArr[0]){
            arr.push(leftArr.shift());
        }else{
            arr.push(rightArr.shift());
        }
    }
    return arr.concat(leftArr,rightArr);
}

5. 快速排序
(1)概念:也用到分治的思想,随机取数据中一个元素(一般是最后一个元素),已这个元素为中点,将小与它的元素
放到它的左边,将大于它的元素放到它的右边。再以它的索引分成两个数据,每个数据重复以上逻辑,实现排序。
(2)特点:
分治思想,用到递归。分治是一种解决问题的处理思想,递归是一种编程技巧。
时间复杂度:O(nlogn),最好情况时间复杂度O(nlogn),最坏情况时间复杂度O(n2),平均时间复杂度O(nlogn)。
空间复杂度O(1)。
稳定性-不稳定。
(3)代码:

function sort(arr,leftIndex=0,rightIndex=arr.length-1){
    if(leftIndex>=rightIndex){return;}
    let storeIndex=partition(arr,leftIndex,rightIndex);
    sort(arr,leftIndex,storeIndex-1);
    sort(arr,storeIndex+1,rightIndex);
}
function partition(arr,leftIndex,rightIndex){
    let pivo=arr[rightIndex];
    let storeIndex=leftIndex;
    for(let i=leftIndex;i<rightIndex;i++){
        if(arr[i]<pivo){
            if(storeIndex!=i){
                [arr[i],arr[storeIndex]]=[arr[storeIndex],arr[i]];
            }
            storeIndex++;
        }
    }
    if(storeIndex!=rightIndex){
        [arr[rightIndex],arr[storeIndex]]=[arr[storeIndex],arr[rightIndex]];
    }
    return storeIndex;
}
function quickSort(arr){
    if(arr.length<=1){
        return arr;
    }
    sort(arr);
    return arr;
}

归并排序和快速排序的区别:可以发现,归并排序的处理过程是由下到上的,先处理子问题,然后再合并。而快排正好相反,它的处理过程是由上到下的,先分区,然后再处理子问题。归并排序虽然是稳定的、时间复杂度为 O(nlogn) 的排序算法,但是它是非原地排序算法。我们前面讲过,归并之所以是非原地排序算法,主要原因是合并函数无法在原地执行。快速排序通过设计巧妙的原地分区函数,可以实现原地排序,解决了归并排序占用太多内存的问题。


aa03ae570dace416127c9ccf9db8ac05.jpg

二、查找

1. 二分法(折半查找)
(1)概念:二分法针对的事一个有序的数据集合,查找思想有点类似与分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小之前的一般,直到找到要查找到元素,或者区间被缩小到0.
(2)特点:
时间复杂度O(logn)
空间复杂度:O(1)
局限性:
二分查找依赖的顺序表解构,也就是数组。
二分查找针对的事有序数据。
数据量太小不适合二分查找。
数据量太大不适合二分查找,底层依赖数据数据结构,要求内存空间连续。

//方法一
function search(arr,value,low=0,high=arr.length-1){
    if(low>high){
        return -1;
    }
    let middleIndex=Math.floor(low+(high-low)/2);
    if(arr[middleIndex]<value){
        return search(arr,value,middleIndex+1,high);
    }else if(arr[middleIndex]>value){
        return search(arr,value,low,middleIndex-1);
    }else{
        return middleIndex
    }
}
//方法二
function serach2(arr,value,low=0,high=arr.length-1){
    while(low<=high){
        let middleIndex=Math.floor(low+(high-low)/2);
        if(arr[middleIndex]<value){
            low=middleIndex+1;
        }else if(arr[middleIndex]>value){
            high=middleIndex-1;
        }else{
            return middleIndex;
        }
    }
    return -1;
}

2.变体二分查找

//找到第一个等于value的值
function searchFirstOfSame(arr,value,low=0,high=arr.length-1){
    if(low>high){
        return -1;
    }
    let middleIndex=Math.floor(low+(high-low)/2);
    if(arr[middleIndex]<value){
        return search(arr,value,middleIndex+1,high);
    }else if(arr[middleIndex]>value){
        return search(arr,value,low,middleIndex-1);
    }else{
        if(arr[middleIndex]==arr[0]||arr[middleIndex]!=arr[middleIndex-1]){return middleIndex} 
        return search(arr,value,low,middleIndex-1);
    }
}
//找到最后一个等于value的值
function searchLastOfSame(arr,value,low=0,high=arr.length-1){
    if(low>high){
        return -1;
    }
    let middleIndex=Math.floor(low+(high-low)/2);
    if(arr[middleIndex]<value){
        return searchLastOfSame(arr,value,middleIndex+1,high);
    }else if(arr[middleIndex]>value){
        return searchLastOfSame(arr,value,low,middleIndex-1);
    }else{
        if(arr[middleIndex]==arr[arr.length-1]||value!=arr[middleIndex+1]){return middleIndex} 
        return searchLastOfSame(arr,value,middleIndex+1,high);
    }
}

三、二叉树

1. 树概念:
(1)父节点、子节点、兄弟节点、根节点、叶子节点
(2)节点高度:节点到叶子节点最长路径(边数)
(3)节点的深度:根节点到这个节点所经历的边的个数
(4)节点的层数:节点的深度+1
(5)树的高度:根节点的高度

2. 二叉树概念:
(1)二叉树:每个节点最多有两个叉,也就是两个节点,分别是左子节点,右子节点
(2)满二叉树:除了叶子节点以外,每个节点都有两个左右子节点
(3)完全二叉树:最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都达到最大

3.二叉树的存储:
一种是局域指针或者引用的二叉链式存储法(大多数都是这种),一种是基于数组的顺序存储法。

WechatIMG1.jpeg

WechatIMG2.jpeg

4.二叉树的遍历:
(1)前(根)序遍历:对树中任意节点,先打印这个节点,再打印左子树,最后打印右子树
(2)中(根)序遍历:对树中任意节点,先打印左子树,再打印它本身,最后打印右子树
(3)后(根)序遍历:对于树中任意节点,先打印左子树,再打印右子树,最后打印它本身
(4)代码:
WX20190330-213653@2x.png

5.二叉树的查找:
(1)特性:要求在树中任意子节点,其左子树中的每个节点值,都要小于这个节点的值,而右子树节点的值都要大于这个节点的值。
(1)代码:
WX20190330-214115@2x.png

6.二叉树的插入操作:
(1)特性:新插入的数据一般都在叶子节点上,需要从根节点开始,依次比较要插入的数据和节点和大小关系。如果要插入的数据比节点数据大,并且节点的右子树为空,就将新数据直接插入到右子节点的位置;如果不为空,就再遍历右子树,查找插入的位置。反之左子树同理。
(2)代码:
WX20190330-214659@2x.png

7.二叉树的删除操作:
WechatIMG3.jpeg

8.二叉树查找、插入、删除时间复杂度:
(1)最坏情况:二叉树退化成链表O(n)
(2)最好情况:完全二叉树和满二叉树O(logn2n)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353