JS数据结构复习随笔

目录

节点结构:

插入:

删除:

查找:

队列

节点结构:

插入:

删除:

查找:

优先级队列

节点结构:

插入:

链表

节点结构:

链表结构:

插入:

删除:

查找:

补充:

双向链表

节点结构:

双向链表结构:

插入:

删除:

查找:

补充:

哈希表

特点

哈希化

哈希函数

哈希表

哈希冲突

        1、链地址法

        2、开放地址法

哈希函数的实现

哈希表结构

插入:

删除:

查找:

哈希扩容

补充:

二叉查找树

特点:

节点结构:

插入:

遍历:

查找

删除:

红黑树

术语:

图结构

        邻接矩阵

        邻接表

        结构:

        插入: 

         遍历:

排序

冒泡排序

代码

总结

选择排序

代码

总结

快速排序

代码

总结:

希尔排序

代码

总结:

插入排序

代码

总结:


节点结构:

         data

  var items = []

插入:

  this.push = function (element) {
            items.push(element)
        }

删除:

 this.pop = function () {
            return items.pop()
        }

查找:

        this.peek = function () {
            return items[items.length - 1]
        }

队列

节点结构:

        data

   var items = []

插入:

 this.enqueue = function (element) {
            items.push(element)
        }

删除:

this.dequeue = function () {
            return items.shift()
        }

查找:

 this.front = function () {
            return items[0]
        }

优先级队列

节点结构:

        data,priority

 function QueueElement(element, priority) {
            this.element = element
            this.priority = priority
        }

插入:

 this.enqueue = function (element, priority) {
            // 1.根据传入的元素, 创建新的QueueElement
            var queueElement = new QueueElement(element, priority)

            // 2.获取传入元素应该在正确的位置
            if (this.isEmpty()) {
                items.push(queueElement)
            } else {
                var added = false
                for (var i = 0; i < items.length; i++) {
                    // 注意: 我们这里是数字越小, 优先级越高
                    if (queueElement.priority < items[i].priority) {
                        items.splice(i, 0, queueElement)
                        added = true
                        break
                    }
                }

                // 遍历完所有的元素, 优先级都大于新插入的元素时, 就插入到最后
                if (!added) {
                    items.push(queueElement)
                }
            }

链表

节点结构:

        data,next

function Node(element) {
            this.element = element
            this.next = null
        }

链表结构:

        node,length,head,api

function Node(element) {
            this.element = element
            this.next = null
        }

        // 链表中的属性
        this.length = 0
        this.head = null

插入:

// 根据下标插入元素
        LinkedList.prototype.insert = function (position, element) {
            // 1.检测越界问题: 越界插入失败
            if (position < 0 || position > this.length) return false

            // 2.定义变量, 保存信息
            var newNode = new Node(element)
            var current = this.head
            var previous = null
            index = 0

            // 3.判断是否列表是否在第一个位置插入
            if (position == 0) {
                newNode.next = current
                this.head = newNode
            } else {
                while (index++ < position) {
                    previous = current
                    current = current.next
                }

                newNode.next = current
                previous.next = newNode
            }

            // 4.length+1
            this.length++

            return true
        }

删除:

// 根据位置移除节点
        LinkedList.prototype.removeAt = function (position) {
            // 1.检测越界问题: 越界移除失败, 返回null
            if (position < 0 || position >= this.length) return null

            // 2.定义变量, 保存信息
            var current = this.head
            var previous = null
            var index = 0

            // 3.判断是否是移除第一项
            if (position === 0) {
                this.head = current.next
            } else {
                while (index++ < position) {
                    previous = current
                    current = current.next
                }

                previous.next = current.next
            }

            // 4.length-1
            this.length--

            // 5.返回移除的数据
            return current.element
        }

查找:

 // 根据元素获取链表中的位置
        LinkedList.prototype.indexOf = function (element) {
            // 1.定义变量, 保存信息
            var current = this.head
            index = 0

            // 2.找到元素所在的位置
            while (current) {
                if (current.element === element) {
                    return index
                }
                index++
                current = current.next
            }

            // 3.来到这个位置, 说明没有找到, 则返回-1
            return -1
        }

补充:

1、查找,添加等方法多借用新定义current来完成遍历等操作

2、删除,添加操作:借助current和previou两个指针分别指向插入位置和插入之前的位置


双向链表

节点结构:

        data,next,pre

function Node(element) {
            this.element = element
            this.next = null
            this.prev = null // 新添加的
        }

双向链表结构:

        node,head,tail,length,api

// 创建节点构造函数
        function Node(element) {
            this.element = element
            this.next = null
            this.prev = null // 新添加的
        }

        // 定义属性
        this.length = 0
        this.head = null
        this.tail = null // 新添加的

插入:

 DoublyLinkedList.prototype.insert = function (position, element) {
            // 1.判断越界的问题
            if (position < 0 || position > this.length) return false

            // 2.创建新的节点
            var newNode = new Node(element)

            // 3.判断插入的位置
            if (position === 0) { // 在第一个位置插入数据
                // 判断链表是否为空
                if (this.head == null) {
                    this.head = newNode
                    this.tail = newNode
                } else {
                    this.head.prev = newNode
                    newNode.next = this.head
                    this.head = newNode
                }
            } else if (position === this.length) { // 插入到最后的情况
                // 思考: 这种情况是否需要判断链表为空的情况呢? 答案是不需要, 为什么?
                this.tail.next = newNode
                newNode.prev = this.tail
                this.tail = newNode
            } else { // 在中间位置插入数据
                // 定义属性
                var index = 0
                var current = this.head
                var previous = null

                // 查找正确的位置
                while (index++ < position) {
                    previous = current
                    current = current.next
                }

                // 交换节点的指向顺序
                newNode.next = current
                newNode.prev = previous
                current.prev = newNode
                previous.next = newNode
            }

            // 4.length+1
            this.length++

            return true
        }

删除:

// 根据位置删除对应的元素
        DoublyLinkedList.prototype.removeAt = function (position) {
            // 1.判断越界的问题
            if (position < 0 || position >= this.length) return null

            // 2.判断移除的位置
            var current = this.head
            if (position === 0) {
                if (this.length == 1) {
                    this.head = null
                    this.tail = null
                } else {
                    this.head = this.head.next
                    this.head.prev = null
                }
            } else if (position === this.length -1) {
                current = this.tail
                this.tail = this.tail.prev
                this.tail.next = null
            } else {
                var index = 0
                var previous = null

                while (index++ < position) {
                    previous = current
                    current = current.next
                }

                previous.next = current.next
                current.next.prev = previous
            }

            // 3.length-1
            this.length--

            return current.element
        }

查找:

// 根据元素获取在链表中的位置
        DoublyLinkedList.prototype.indexOf = function (element) {
            // 1.定义变量保存信息
            var current = this.head
            var index = 0

            // 2.查找正确的信息
            while (current) {
                if (current.element === element) {
                    return index
                }
                index++
                current = current.next
            }

            // 3.来到这个位置, 说明没有找到, 则返回-1
            return -1
        }

补充:

1、双向链表的插入与删除都需要考虑空,第一个,最后一个,中间四种情况

2、链表此类一般先借用head,tail进行操作最后改正head

3、插入删除要考虑四根指针


哈希表

特点

        1、提供极快的插入删除,查找,操作。

        2、数据无序,key值不重复

哈希化

        将大数字转换成数组范围内下标的过成,被称为哈希化

哈希函数

        哈希化的代码实现放在一个函数中,此函数被称为哈希函数

哈希表

        最终将数据插入到的数组,对整个结构的封装我们称之为哈希表

        相当于可以将数组的内容与下标相关联,通过查找下标的方式来查找内容

哈希冲突

        1、链地址法

                        若有重复,将重复的数据插入到链表的首段或末端

        2、开放地址法

                寻找空白来存放

                        1、线性探测

                                若重复,下标x+1,,x+2 ,...

                        2、二次探测

                                若重复,下标x+1^2  ,x+2^2,....

                        3、再次哈希

                                把关键字用另一个哈希函数再次哈希化得到步长,x+hash(x)

                                           

哈希函数的实现

得到hashcode,来确定要放在哪里

function hashFunc(str, max) {
        // 1.初始化hashCode的值
        var hashCode = 0

        // 2.霍纳算法, 来计算hashCode的数值
        for (var i = 0; i < str.length; i++) {
            hashCode = 37 * hashCode + str.charCodeAt(i)
        }

        // 3.取模运算
        hashCode = hashCode % max
        return hashCode
    }
//max:数组最大长度

哈希表结构

        this.storage = []    //存放数据的数组
        this.count = 0        //占了多少位置
        this.limit = 8        //哈希表的大小

插入:

// 插入数据方法
        HashTable.prototype.put = function (key, value) {
            // 1.获取key对应的index
            var index = this.hashFunc(key, this.limit)

            // 2.取出数组(也可以使用链表)
            // 数组中放置数据的方式: [[ [k,v], [k,v], [k,v] ] , [ [k,v], [k,v] ]  [ [k,v] ] ]
            var bucket = this.storage[index]

            // 3.判断这个数组是否存在
            if (bucket === undefined) {
                // 3.1创建桶
                bucket = []
                this.storage[index] = bucket
            }

            // 4.判断是新增还是修改原来的值.
            var override = false
            for (var i = 0; i < bucket.length; i++) {
                var tuple = bucket[i]
                if (tuple[0] === key) {
                    tuple[1] = value
                    override = true
                }
            }

            // 5.如果是新增, 前一步没有覆盖
            if (!override) {
                bucket.push([key, value])
                this.count++

                if (this.count > this.limit * 0.75) {
                    var primeNum = this.getPrime(this.limit * 2)
                    this.resize(primeNum)
                }
            }
        }

删除:

 // 删除数据
        HashTable.prototype.remove = function (key) {
            // 1.获取key对应的index
            var index = this.hashFunc(key, this.limit)

            // 2.获取对应的bucket
            var bucket = this.storage[index]

            // 3.判断同是否为null, 为null则说明没有对应的数据
            if (bucket == null) {
                return null
            }

            // 4.遍历bucket, 寻找对应的数据
            for (var i = 0; i < bucket.length; i++) {
                var tuple = bucket[i]
                if (tuple[0] === key) {
                    bucket.splice(i, 1)
                    this.count--

                    // 缩小数组的容量
                    if (this.limit > 7 && this.count < this.limit * 0.25) {
                        var primeNum = this.getPrime(Math.floor(this.limit / 2))
                        this.resize(primeNum)
                    }
                }
                return tuple[1]
            }

            // 5.来到该位置, 说明没有对应的数据, 那么返回null
            return null
        }

查找:

 // 获取存放的数据
        HashTable.prototype.get = function (key) {
            // 1.获取key对应的index
            var index = this.hashFunc(key, this.limit)

            // 2.获取对应的bucket
            var bucket = this.storage[index]

            // 3.如果bucket为null, 那么说明这个位置没有数据
            if (bucket == null) {
                return null
            }

            // 4.有bucket, 判断是否有对应的key
            for (var i = 0; i < bucket.length; i++) {
                var tuple = bucket[i]
                if (tuple[0] === key) {
                    return tuple[1]
                }
            }

            // 5.没有找到, return null
            return null
        }

哈希扩容

 // 哈希表扩容
        HashTable.prototype.resize = function (newLimit) {
            // 1.保存旧的数组内容
            var oldStorage = this.storage

            // 2.重置属性
            this.limit = newLimit
            this.count = 0
            this.storage = []

            // 3.遍历旧数组中的所有数据项, 并且重新插入到哈希表中
            oldStorage.forEach(function (bucket) {
                // 1.bucket为null, 说明这里面没有数据
                if (bucket == null) {
                    return
                }

                // 2.bucket中有数据, 那么将里面的数据重新哈希化插入
                for (var i = 0; i < bucket.length; i++) {
                    var tuple = bucket[i]
                    this.put(tuple[0], tuple[1])
                }
            }).bind(this)
        }

补充:

        哈希表算法大多按步骤

                        1、由key获取index

                        2、据index获取bucket,判断是否存在

                        3、线性查找


二叉查找树

特点:

        左子树>根节点>右子树

节点结构:

 function Node(key) {
            this.key = key
            this.left = null
            this.right = null
        }

插入:

二叉树方法基本都用上了递归。

// 向树中插入数据
        BinarySerachTree.prototype.insert = function (key) {
            // 1.根据key创建对应的node
            var newNode = new Node(key)

            // 2.判断根节点是否有值
            if (this.root === null) {
                this.root = newNode
            } else {
                this.insertNode(this.root, newNode)
            }
        }

        BinarySerachTree.prototype.insertNode = function (node, newNode) {
            if (newNode.key < node.key) { // 1.准备向左子树插入数据
                if (node.left === null) { // 1.1.node的左子树上没有内容
                    node.left = newNode
                } else { // 1.2.node的左子树上已经有了内容
                    this.insertNode(node.left, newNode)
                }
            } else { // 2.准备向右子树插入数据
                if (node.right === null) { // 2.1.node的右子树上没有内容
                    node.right = newNode
                } else { // 2.2.node的右子树上有内容
                    this.insertNode(node.right, newNode)
                }
            }
        }

遍历:

 // 遍历方法
        // 先序遍历
        BinarySerachTree.prototype.preOrderTraversal = function (handler) {
            this.preOrderTranversalNode(this.root, handler)
        }

        BinarySerachTree.prototype.preOrderTranversalNode = function (node, handler) {
            if (node !== null) {
                handler(node.key)
                this.preOrderTranversalNode(node.left, handler)
                this.preOrderTranversalNode(node.right, handler)
            }
        }

        // 中序遍历
        BinarySerachTree.prototype.inOrderTraversal = function (handler) {
            this.inOrderTraversalNode(this.root, handler)
        }

        BinarySerachTree.prototype.inOrderTraversalNode = function (node, handler) {
            if (node !== null) {
                this.inOrderTraversalNode(node.left, handler)
                handler(node.key)
                this.inOrderTraversalNode(node.right, handler)
            }
        }

        // 后续遍历
        BinarySerachTree.prototype.postOrderTraversal = function (handler) {
            this.postOrderTraversalNode(this.root, handler)
        }

        BinarySerachTree.prototype.postOrderTraversalNode = function (node, handler) {
            if (node !== null) {
                this.postOrderTraversalNode(node.left, handler)
                this.postOrderTraversalNode(node.right, handler)
                handler(node.key)
            }
        }

查找

与遍历不同,其为return

 BinarySerachTree.prototype.search = function (key) {
            return this.searchNode(this.root, key)
        }

        BinarySerachTree.prototype.searchNode = function (node, key) {
            // 1.如果传入的node为null那么, 那么就退出递归
            if (node === null) {
                return false
            }

            // 2.判断node节点的值和传入的key大小
            if (node.key > key) { // 2.1.传入的key较小, 向左边继续查找
                return this.searchNode(node.left, key)
            } else if (node.key < key) { // 2.2.传入的key较大, 向右边继续查找
                return this.searchNode(node.right, key)
            } else { // 2.3.相同, 说明找到了key
                return true
            }
        }

删除:

        思路:

  • 找到删除的节点
    • 叶节点:直接删除
    • 有一个子节点的节点:
      • 判断是该节点是有左子树还是有右子树(current.left==null)
      • 判断该节点在父节点的左还是右(isLeft)
      • 爷孙链接
    • 有两个子节点的节点:
      • 找前驱/后继(左子树最大值/右子树最小值) 
        • 循环找后继
        • 若后继非删除子节点直接子节点,1、将删除节点右子树赋值给后继,2、将后继父节点与后继子节点链接
      • 父节点与后继链接
      • 将删除节点的左子树给后继

需要三个变量:current  parent  isLeft

每一次都要考虑,根节点,左子树,右子树

        // 删除结点
        BinarySerachTree.prototype.remove = function (key) {
            // 1.定义临时保存的变量
            var current = this.root
            var parent = this.root
            var isLeftChild = true

            // 2.开始查找节点
            while (current.key !== key) {
                parent = current
                if (key < current.key) {
                    isLeftChild = true
                    current = current.left
                } else {
                    isLeftChild = false
                    current = current.right
                }

                // 如果发现current已经指向null, 那么说明没有找到要删除的数据
                if (current === null) return false
            }

            // 3.删除的结点是叶结点
            if (current.left === null && current.right === null) {
                if (current == this.root) {
                    this.root == null
                } else if (isLeftChild) {
                    parent.left = null
                } else {
                    parent.right = null
                }
            }

            // 4.删除有一个子节点的节点
            else if (current.right === null) {
                if (current == this.root) {
                    this.root = current.left
                } else if (isLeftChild) {
                    parent.left = current.left
                } else {
                    parent.right = current.left
                }
            } else if (current.left === null) {
                if (current == this.root) {
                    this.root = current.right
                } else if (isLeftChild) {
                    parent.left = current.right
                } else {
                    parent.right = current.right
                }
            }

            // 5.删除有两个节点的节点
            else {
                // 1.获取后继节点
                var successor = this.getSuccessor(current)

                // 2.判断是否是根节点
                if (current == this.root) {
                    this.root = successor
                } else if (isLeftChild) {
                    parent.left = successor
                } else {
                    parent.right = successor
                }

                // 3.将删除节点的左子树赋值给successor
                successor.left = current.left
            }

            return true
        }

        // 找后继的方法
        BinarySerachTree.prototype.getSuccessor = function (delNode) {
            // 1.使用变量保存临时的节点
            var successorParent = delNode
            var successor = delNode
            var current = delNode.right // 要从右子树开始找

            // 2.寻找节点
            while (current != null) {
                successorParent = successor
                successor = current
                current = current.left
            }

            // 3.如果是删除图中15的情况, 还需要如下代码
            if (successor != delNode.right) {
                successorParent.left = successorParent.right
                successor.right = delNode.right
            }
        }

  • 哈夫曼树与编码

    • 待补充
  • AVL树

    • 待补充
  • B 树与 B+ 树

    • 待补充

红黑树

待补充....


术语:

  • 度:相邻顶点的数量
  • 简单路径:不包含重复的顶点
  • 回路:第一个顶点与最后一个顶点相同的路径

图结构

        邻接矩阵

                让每个节点和一个整数相关联,整数作为数组的下标值

                用一个二维数组表示顶点之间的联系

        邻接表

                 由图中每个顶点以及和顶点相邻的定点列表组成

        

        结构:

 // 属性
        this.vertexes = [] // 存储顶点
        this.adjList = new Dictionay() // 存储边

        插入: 

// 添加方法
        //添加顶点
        Graph.prototype.addVertex = function (v) {
            this.vertexes.push(v)
            this.adjList.set(v, [])
        }
        // 添加边
        Graph.prototype.addEdge = function (v, w) {
            this.adjList.get(v).push(w)
            this.adjList.get(w).push(v)
        }

         遍历:

广度优搜索(BFS)

基于队列,入队列的顶点先被搜索

// 广度优先算法
        Graph.prototype.bfs = function (v, handler) {
            // 1.初始化颜色
            var color = this.initializeColor()

            // 2.创建队列
            var queue = new Queue()

            // 3.将传入的顶点放入队列中
            queue.enqueue(v)

            // 4.从队列中依次取出和放入数据
            while (!queue.isEmpty()) {
                // 4.1.从队列中取出数据
                var qv = queue.dequeue()

                // 4.2.获取qv相邻的所有顶点
                var qAdj = this.adjList.get(qv)

                // 4.3.将qv的颜色设置成灰色
                color[qv] = "gray"

                // 4.4.将qAdj的所有顶点依次压入队列中
                for (var i = 0; i < qAdj.length; i++) {
                    var a = qAdj[i]
                    if (color[a] === "white") {
                        color[a] = "gray"
                        queue.enqueue(a)
                    }
                }

                // 4.5.因为qv已经探测完毕, 将qv设置成黑色
                color[qv] = "black"

                // 4.6.处理qv
                if (handler) {
                    handler(qv)
                }
            }

深度优先搜索(DFS)

基于栈或递归,将顶点存入栈中,顶点是沿着路经被探索的,存在新的相邻顶点就访问

 // dfs的递归调用方法
        Graph.prototype.dfsVisit = function (u, color, handler) {
            // 1.将u的颜色设置为灰色
            color[u] = "gray"

            // 2.处理u顶点
            if (handler) {
                handler(u)
            }

            // 3.u的所有邻接顶点的访问
            var uAdj = this.adjList.get(u)
            for (var i = 0; i < uAdj.length; i++) {
                var w = uAdj[i]
                if (color[w] === "white") {
                    this.dfsVisit(w, color, handler)
                }
            }

            // 4.将u设置为黑色
            color[u] = "black"
        }

  • 最短路径算法:Floyd,Dijkstra

    • 待补充
  • 最小生成树算法:Prim,Kruskal

    • 待补充

排序

冒泡排序

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • 针对所有的元素重复以上的步骤,除了最后一个;
  • 重复步骤1~3,直到排序完成。

代码

function bubbleSort(arr) {
     var  len = arr.length;
     for  ( var  i = 0; i < len; i++) {
         for  ( var  j = 0; j < len - 1 - i; j++) {
             if  (arr[j] > arr[j+1]) {        //相邻元素两两对比
                 var  temp = arr[j+1];        //元素交换
                 arr[j+1] = arr[j];
                 arr[j] = temp;
             }
         }
     }
     return  arr;
}

总结

        内层循环:执行冒泡操作(冒泡的过程随次数缩短)

        外层循环:控制冒泡次数


选择排序

  • 初始状态:无序区为R[1..n],有序区为空;
  • 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
  • n-1趟结束,数组有序化了。

代码

function selectionSort(arr) {
     var  len = arr.length;
     var  minIndex, temp;
     for  ( var  i = 0; i < len - 1; i++) {
         minIndex = i;
         for  ( var  j = i + 1; j < len; j++) {
             if  (arr[j] < arr[minIndex]) {     //寻找最小的数
                 minIndex = j;                 //将最小数的索引保存
             }
         }
         temp = arr[i];
         arr[i] = arr[minIndex];
         arr[minIndex] = temp;
     }
     return  arr;
}

总结

        内层循环:寻找无序区中最小的数

        外层循环:控制增加有序区数据(与最小交换)


快速排序

        

  • 从数列中挑出一个元素,称为 “基准”(pivot);
  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;(通过两个指针实现)
  • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

代码

// 选择枢纽
        ArrayList.prototype.median = function (left, right) {
            // 1.求出中间的位置
            var center = Math.floor((left + right) / 2)

            // 2.判断并且进行交换
            if (this.array[left] > this.array[center]) {
                this.swap(left, center)
            }
            if (this.array[center] > this.array[right]) {
                this.swap(center, right)
            }
            if (this.array[left] > this.array[right]) {
                this.swap(left, right)
            }

            // 3.巧妙的操作: 将center移动到right - 1的位置.
            this.swap(center, right - 1)

            // 4.返回pivot
            return this.array[right - 1]
        }

        // 快速排序实现
        ArrayList.prototype.quickSort = function () {
            this.quickSortRec(0, this.array.length - 1)
        }

        ArrayList.prototype.quickSortRec = function (left, right) {
            // 0.递归结束条件
            if (left >= right) return

            // 1.获取枢纽
            var pivot = this.median(left, right)

            // 2.开始进行交换
            var i = left
            var j = right - 1
            while (true) {
                while (this.array[++i] < pivot) { }//1、左边碰见大于枢纽,停下
                while (this.array[--j] > pivot) { }//2、右边碰见小于枢纽,停下
                if (i < j) {
                    this.swap(i, j)                //3、i<j交换
                } else {
                    break
                }
            }

            // 3.将枢纽放在正确的位置                //4、放正确位置
            this.swap(i, right - 1)

            // 4.递归调用左边
            this.quickSortRec(left, i - 1)
            this.quickSortRec(i + 1, right)
        }

总结:

            以分而治之为核心思想


希尔排序

  • 选择增量(gap),将数据分组
  • 对每组数据进行插入排序
  • 逐渐减少增量,直至为1

代码

 ArrayList.prototype.shellSort = function () {
            // 1.获取数组的长度
            var length = this.array.length

            // 2.根据长度计算增量
            var gap = Math.floor(length / 2)

            // 3.增量不断变量小, 大于0就继续排序
            while (gap > 0) {
                // 4.实现插入排序
                for (var i = gap; i < length; i++) {    //获取数据加入有序,不同分组                            
                                                         //  交替插入
                    // 4.1.保存临时变量
                    var j = i                        //找位置的指针
                    var temp = this.array[i]        //存起来

                    // 4.2.插入排序的内存循环
                    while (j > gap - 1 && this.array[j - gap] > temp) {
                        this.array[j] = this.array[j - gap] //元素后移
                        j -= gap                           //指针向前推进寻找合适位置
                    }

                    // 4.3.将选出的j位置设置为temp        
                    this.array[j] = temp                //根据指针插入
                }

                // 5.重新计算新的间隔
                gap = Math.floor(gap / 2)
            }
        }

总结:

         外层循环:控制分组增量(gap)逐渐减少,直至为1

        中间循环:获取数据加入有序

        内层循环:寻找位置

        中外内共同完成插入排序


插入排序

        

  • 从第一个元素开始,该元素可以认为已经被排序;
  • 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  • 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  • 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  • 将新元素插入到该位置后;
  • 重复步骤2~5。

代码

function insertionSort(arr) {
     var  len = arr.length;
     var  preIndex, current;
     for  ( var  i = 1; i < len; i++) {
         preIndex = i - 1;                    //有序的边界,i为无需第一个
         current = arr[i];                //先存起来
         while (preIndex >= 0 && arr[preIndex] > current) {
             arr[preIndex+1] = arr[preIndex];
             preIndex--;                    //用于查找位置的指针
         }
         arr[preIndex+1] = current;        //,根据指针插入
     }
     return  arr;
}

总结:

  •  选择排序,先从无序区找最小加入有序区
  •  插入排序,从无序区找一个,依次与有序区比较直至合适位置

外层循环:从第1个位置开始获取数据,向有序区插入

内层循环:与有序区的数据依次比较,找到合适位置(若大则后移)

        

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值