js 快排与冒泡

虽然说算法很复杂,但是在我的工作经验中,掌握这2个基本就够处理大部分前端业务工作(不要跟我抬杠哦,你要面试肯定不够用),所以总结一下~~

快排

const quickSort = l => {
    if (l.length < 2) {
        return l
    }
    // 我就把每次数组第一个元素当基点  这样理解简单
    let pivot = l[0]
    let left = []
    let right = []
    l.slice(1).forEach(e => {
        if (e >= pivot) {
            right.push(e)
        } else {
            left.push(e)
        }
    })
    return quickSort(left)
        .concat(pivot)
        .concat(quickSort(right))
}

冒泡

// 相邻元素两两对比,元素交换,大的元素交换到后面
const jsSort = l => {
    let len = l.length
    for (let i = 0; i < len - 1; i++) {
        for (let j = 0; j < len - 1 - i; j++) {
            if (l[j] > l[j + 1]) {
                const e = l[j]
                l[j] = l[j + 1]
                l[j + 1] = e
            }
        }
    }
    return l
}

如果为了面试, 你可能需要知道下面这些

class Node {
    constructor(x) {
        this.element = x
        this.next = null
    }
}

class LinkedList {
    constructor() {
        this.head = null
    }

    length() {
        let index = 0
        let node = this.head
        while (node != null) {
            index += 1
            node = node.next
        }
        return index
    }

    lastNode() {
        // 2, 返回单链表的最后一个节点
        // 找到最后一个 Node
        let n = this.head
        while (n != null) {
            if (n.next === null) {
                return n
            }
            n = n.next
        }
        return n
    }

    kthNode(i) {
        // 3, 返回单链表第 i 个节点
        let n = this.head
        let index = 0
        while (n != null) {
            if (index + 1 == i) {
                return n
            }
            n = n.next
            index++
        }
        return n
    }

    nLast(x) {
        // 4, 返回单链表倒数第 n 个节点
        let len = this.length()
        let index = len - x
        return this.kthNode(index)
    }

    hasX(x) {
        // 5, 判断单链表中是否有值为 x 的节点
        let n = this.head
        while (n != null) {
            if (n.element == x) {
                return true
            }
            n = n.next
        }
        return false
    }

    middle() {
        // 6, 查找单链表的中间节点
        if (this.length() % 2 === 0) {
            return null
        } else {
            let index = Math.floor(this.length() / 2)
            return this.kthNode(index)
        }
    }

    append(e) {
        // 7, 给单链表末尾插入一个节点
        let node = new Node(e)
        // 找到最后一个 Node
        let n = this.head
        if (n == null) {
            this.head = node
        } else {
            while (n.next != null) {
                n = n.next
            }
            n.next = node
        }
        return this
    }

    prepend(x) {
        // 8, 给单链表头部插入一个元素
        let node = new Node(x)
        node.next = this.head
        this.head = node
        return this
    }

    insertAfter(n, x) {
        // 9, 给单链表第 n 个节点后插入一个元素
        let node = new Node(x)
        let index = 0
        let node2 = this.head
        while (n != null) {
            if (index == n) {
                break
            }
            node2 = node2.next
            index++
        }
        node.next = node2.next
        node2.next = node
        return this
    }

    insertLastN(n, x) {
        // 10, 给单链表倒数第 n 个节点前插入一个元素
        let nn = this.nLast(n)
        if (nn != null) {
            if (nn == this.head) {
                this.prepend(x)
            } else {
                let node = new Node(x)
                let nn = this.nLast(n + 1)
                node.next = nn.next
                nn.next = node
            }
        }
        return this
    }

    deleteN(n) {
        // 11, 删除单链表第 n 个节点
        if (n == 0) {
            let node = this.head
            this.head = this.head.next
            return node.element
        } else {
            let node = this.kthNode(n - 1)
            if (node != null && node.next) {
                let dlete_node = node.next
                node.next = node.next.next
                return dlete_node.element
            }
        }
    }

    deleteX(x) {
        // 12, 删除单链表中值为 x 的节点
        let n = this.head
        if (n && n.element == x) {
            return this.deleteN(0)
        }
        while (n != null) {
            if (n.next && n.next.element == x) {
                n.next = n.next.next
                break
            }
            n = n.next
        }
        return this
    }

    deleteLastN(n) {
        // 13, 删除单链表倒数第 n 个节点
        let index = this.length() - n
        return this.deleteN(index)
    }

    // 返回反转后的单链表
    reverse() {
        let node = this.head
        let new_node = null
        while (node != null && node.next != null) {
            new_node = node.next
            node.next = new_node.next
            new_node.next = this.head
            this.head = new_node
        }
        return this
    }

    isPalindrome() {
        // 15, 判断一个链表是否是回文链表 回文链表自己查加深印象
        let new_linked_list = this.reverse()
        return JSON.stringify(new_linked_list) == JSON.stringify(this)
    }

    isCircle() {
        // 16, 判断一个链表是否是环形链表 不懂自己查加深印象
        // 本题用双指针, a 一次走一格 b 一次走两格,如果相遇说明有环形 这个方法时间空间复杂度是最优解
        let slow = this.head
        let fast = this.head.next
        while (fast && fast.next) {
            if (slow == fast) {
                return true
            }
            slow = slow.next
            fast = fast.next.next
        }
        return false
    }

    copy() {
        // 17, 返回一个单链表的复制
        let new_linked_list = new LinkedList()
        let n = this.head
        while (n != null) {
            new_linked_list.append(n.element)
            n = n.next
        }
        return new_linked_list
    }

    powerCopy() {
        // 18, 返回一个环形链表的复制
        let map = new Map()
        let n = this.head
        let new_linked_list = new LinkedList()
        let index = 0
        while (n != null) {
            if (map.get(n)) {
                break
            }
            map.set(n, true)
            new_linked_list.append(n.element)
            n = n.next
            index++
        }
        return new_linked_list
    }

    _mergeNodeList(l1, l2) {
        if (l1 == null) {
            return l2
        }
        if (l2 == null) {
            return l1
        }
        let node
        if (l1.element < l2.element) {
            node = l1
            node.next = this._mergeNodeList(l1.next, l2)
        } else {
            node = l2
            node.next = this._mergeNodeList(l1, l2.next)
        }

        return node
    }

    mergeList(linkedList) {
        // 19, 合并两个有序链表并保持有序 返回一个新链表
        let n1 = this.head
        let n2 = linkedList.head

        let new_linked_list = new LinkedList()
        let nodeList = this._mergeNodeList(n1, n2)
        new_linked_list.head = nodeList
        return new_linked_list
    }

    josephList(m) {
        // 20, 本题是约瑟夫环问题
        // 1, 2, 3 ..., n 这 n 个数字排成一个圆圈 (首尾相连)
        // 从数字 1 开始每次从这个圆圈里删除第 m 个数字, 删除后从下一位继续从1开始删除第 m 个数字
        // 求出这个圆圈里剩下的最后一个数字
        let n = this.head
        let index = 1
        while (n !== null) {
            if (this.head == this.head.next) {
                console.log('game over', this)
                break
            }
            if (index == m - 1) {
                if (this.head == n.next) {
                    this.head = n.next.next
                }
                n.next = n.next.next
                n = n.next
                index = 1
            } else {
                n = n.next
                index++
            }
        }
    }

    rearrange(x) {
        // 1 给一个单链表和一个值 x, 对它进行分割, 所有小于x的结点排在大于或等于x的结点之前
        let before = new LinkedList()
        let after = new LinkedList()
        let n = this.head
        while (n != null) {
            if (n.element < x) {
                before.append(n.element)
            } else {
                after.append(n.element)
            }
            n = n.next
        }
        let nn = after.head
        while (nn != null) {
            before.append(nn.element)
            nn = nn.next
        }
        return before
    }

    circleHead() {
        // 2 给一个链表, 返回环形链表中环形开始的节点, 如果没有环形, 返回 null
        let slow = this.head
        let fast = this.head.next
        while (fast && fast.next) {
            if (slow == fast) {
                return slow
            }
            slow = slow.next
            fast = fast.next.next
        }
        return null
    }

    _findmiddleList(left) {
        let n = left
        if (n == null || n.next == null) {
            return n
        }
        let slow = left
        let fast = left
        let slow_next = left
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next
            fast = fast.next.next
            slow_next = slow.next
        }
        slow.next = null
        return slow_next
    }

    _reverse(node) {
        // 没有头结点的链表翻转
        if (node == null || node.next == null) {
            return node
        }
        let pre = node
        let cur = node.next
        pre.next = null
        while (cur != null) {
            let tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        }
        return pre
    }

    reorder() {
        // 3
        // 给一个链表, 将原链表 L0 -> L1 -> L2 -> ... -> Ln-1 -> ln 排序为
        // L0 -> L1 -> Ln -> L2 -> Ln-1 -> ...
        // 要求: 不能修改节点的值

        let n = this.head
        if (n == null || n.next == null) {
            return
        }
        let left = this.head.next

        let right = this._findmiddleList(left)
        right = this._reverse(right)

        // 交替合并
        let tmp
        while (left != null || right != null) {
            if (left != null) {
                tmp = left.next
                n.next = left
                left = tmp
                n = n.next
            }
            if (right != null) {
                tmp = right.next
                n.next = right
                right = tmp
                n = n.next
            }
        }

        return this
    }

    rotateList(k) {
        // 4
        // 给一个链表, 将列表向右旋转 k 个下标, 其中 k 是非负数
        // 例子:
        //     Input: 1->2->3->4->5->NULL, k = 2
        //     Output: 4->5->1->2->3->NULL
        //     Input: 0->1->2->NULL, k = 4
        //     Output: 2->0->1->NULL
        // 其实就是移动
        let len = this.length()
        let step = k % len
        let node = this.nLast(step + 1)
        if (node == null) {
            return node
        }
        let n = node.next
        node.next = null
        let head = this.head
        this.head = n
        while (n != null && n.next != null) {
            n = n.next
        }
        n.next = head
        return this
    }
    static quickSort(list) {
        if (list.length < 2) {
            return list
        }
        let left = []
        let right = []
        let p = list[0]
        for (let i = 1; i < list.length; i++) {
            const e = list[i]
            if (e < p) {
                left.push(e)
            } else {
                right.push(e)
            }
        }
        return LinkedList.quickSort(left).concat([p]).concat(LinkedList.quickSort(right))
    }

    _sortmerge(l1, l2) {
        let node = new Node(-1)
        let n = node
        while (l1 != null && l2 != null) {
            if (l1.element < l2.element) {
                n.next = l1
                l1 = l1.next
            } else {
                n.next = l2
                l2 = l2.next
            }
            n = n.next
        }
        if (l1) {
            n.next = l1
        }
        if (l2) {
            n.next = l2
        }

        return node.next
    }

    _sortNodeList(nodeList) {
        let head = nodeList
        if (head == null || head.next == null) {
            return head
        }
        let pre = head
        let slow = head
        let fast = head
        while (fast && fast.next) {
            pre = slow
            slow = slow.next
            fast = fast.next.next
        }
        pre.next = null
        return this._sortmerge(this._sortNodeList(head), this._sortNodeList(slow))
    }

    sortList() {
        //     给一个链表, 将链表排序
        //     要求: 时间复杂度为 O(nlogn)
        let n = this.head
        let nodeList = this._sortNodeList(n)
        this.head = nodeList
        return this
    }

    reverseMn(m, n) {
        // 6
        // 给一个单链表和正整数 m, n(m < n), 从 m 到 n 开始反转
        let start = this.kthNode(m - 1)
        let len = n - m
        while (len > 0) {
            let node = this.kthNode(n - 1)
            let end = node.next
            node.next = node.next.next
            end.next = start.next
            start.next = end
            start = start.next
            len--
        }
        return this
    }

    deduplication() {
        // 7
        // 给一个有序的单链表, 删除所有有重复 value 的节点, 只留下原始列表中不同的 value
        let n = this.head
        if (n == null || n.next == null) {
            return this
        }
        let value = this.head.element
        while (n != null && n.next != null) {
            // 重复
            if (n.next.element == value) {
                n.next = n.next.next
            } else {
                n = n.next
                value = n.element
            }
        }
        return this
    }

    static addNumber(a, b) {
        // 8
        // 给两个非空且长度不一定相同的单链表, 表示两个非负整数
        // 数字以相反的顺序存储(个位在前), 每个节点都包含一个 value, 将两个 value 相加并返回链表
        // 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
        // 输出:7 -> 0 -> 8
        // 原因:342 + 465 = 807

        let num1 = []
        let head_a = a.head
        while (head_a != null) {
            num1.unshift(head_a.element)
            head_a = head_a.next
        }

        let num2 = []
        let head_b = b.head
        while (head_b != null) {
            num2.unshift(head_b.element)
            head_b = head_b.next
        }

        num1 = Number(num1.join(''))
        num2 = Number(num2.join(''))
        let num = num1 + num2 + ''
        num = num.split('')

        let new_linked_list = new LinkedList()
        let head = new_linked_list.head

        num.forEach((i) => {
            let tmp = head
            head = new Node(Number(i))
            head.next = tmp
        })
        new_linked_list.head = head
        return new_linked_list
    }

    static mergeListK(...args) {
        // 9
        // 合并 k 个有序链表并保证有序,要求时间复杂度最优,不会就讨论,乱写没价值
        // args 是一个包含 k 个链表的数组

        if (args.length == 0) {
            return null
        }
        if (args.length == 1) {
            return args[0]
        }
        if (args.length == 2) {
            return args[0].mergeList(args[1])
        }
        let middle = Math.floor(args.length / 2)
        let left = args.slice(0, middle)
        let right = args.slice(middle)
        let l1 = LinkedList.mergeListK(...left)
        let l2 = LinkedList.mergeListK(...right)
        return l1.mergeList(l2)
    }

    reverseListK(k) {
        // 10
        // k 个一组反转链表(25)
        //     给一个链表, 以每 k 个为一组来翻转链表
        //     例子:
        //         Given this linked list: 1->2->3->4->5
        //
        //         k = 2, return: 2->1->4->3->5
        //
        //         k = 3, return: 3->2->1->4->5
        let head = this.head
        if (head == null) {
            return this
        }
        let new_node = new Node(-1)
        new_node.next = head
        let cur = head
        let pre = new_node
        let len = this.length()
        let num = 0
        while (len >= k) {
            while (num < k - 1) {
                let temp = cur.next
                cur.next = temp.next
                temp.next = pre.next
                pre.next = temp
                num++
            }

            num = 0
            pre = cur
            cur = cur.next
            len -= k
        }

        this.head = new_node.next
        return this
    }
}

### 链表 (栈和队列是链表的改良型)


### 队列 (先进先出)


### 栈 (先进后出)


### 哈希表 (Hash table)


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

推荐阅读更多精彩内容

  • part1 初次得知赵先森,是在老妈狂轰乱炸的逼婚下,听了N多次,耳朵都起茧。在老妈的描述下,我想像着他的...
    苒苒angel阅读 595评论 2 2
  • 你是不是他的转世 为什么你们的名字 都来自蜀地 她是长卿前世难忘的情人 你是贵妃后世遗落的丈夫 为什么 你们老是挨...
    白衣小潘安阅读 141评论 0 2
  • 我们刚刚上学的时候,老师都会问我们一个问题“你长大了想做什么?”。那时候,我们回答最多的就是“科学家”、“宇航员”...
    容我34阅读 393评论 1 5
  • 闭上眼睛,好像这个世界很空旷,没有一点声音,只有心跳声,这个时候的感觉 很美很享受。 为了爱我的人无论在明处与暗处...
    无力执着阅读 291评论 0 0
  • 01 王乐是个业余物理学家,说他业余,只是指他没有固定的工作。专业上他可一点也不业余,学术水平甚至比很多教授都高。...
    于无眠处终有梦阅读 633评论 0 4