算法排序

118 阅读2分钟

1.冒泡排序

重复走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到不用再交换

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

2.选择排序

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕

  function selectionSort(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;
  }

3.插入排序

它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间

function insertSort(arr) {
  let len = arr.length;
  for (let i = 1; i < len; i++) {
    let temp = arr[i];
    let j = i - 1; //默认已排序的元素
    while (j >= 0 && arr[j] > temp) {
      //在已排序好的队列中从后向前扫描
      arr[j + 1] = arr[j]; //已排序的元素大于新元素,将该元素移到一下个位置
      j--;
    }
    arr[j + 1] = temp;
  }
  return arr;
}

4.快速排序

在数据集之中,选择一个元素作为”基准”(pivot)。所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止

function quickSort(arr) {
    if (arr.length <= 1) {
      return arr;
    }
    let pivotIndex = Math.floor(arr.length / 2);
    let pivot = arr.splice(pivotIndex, 1)[0];
    let left = [];
    let right = [];
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] < pivot) {
        left.push(arr[i]);
      } else {
        right.push(arr[i]);
      }
    }
    return quickSort(left).concat([pivot], quickSort(right));
}

5. 二分查找

假设数组中元素升序排列,将表中间位置数字与查找数字比较,若相等,则查找成功。否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的数字大于查找数字,则查找前一子表,否则查找后一子表。重复以上过程,直到找到满足条件的记录,则查找成功,或直到子表不存在为止,此时查找不成功

var Arr = [3, 5, 6, 7, 9, 12, 15];
function binary(find, arr, low = 0, high = arr.length - 1) {
    if (low <= high) {
      let mid = Math.ceil((high + low) / 2);
      if (arr[mid] === find) {
        return mid;
      } else if (arr[mid] > find) {
        return binary(find, arr, low, mid - 1);
      } else {
        return binary(find, arr, mid + 1, high);
      }
    }
    return -1;
}
binary(10, Arr);

6. 杨辉三角

var generate = function(numRows) {
    if (numRows) {
        var result = [[1]];
        for (var i = 1; i < numRows; i++) {
            result[i] = [];
            for (var j = 0; j < i + 1; j++) {
                result[i][j] = (result[i - 1][j] || 0) + (result[i - 1][j - 1] || 0);
            }
        }
        return result;
    } else {
        return [];
    }
};
console.log(generate(5));  // [ [ 1 ], [ 1, 1 ], [ 1, 2, 1 ], [ 1, 3, 3, 1 ], [ 1, 4, 6, 4, 1 ] ]
console.log(generate(5)[4]); // [ 1, 4, 6, 4, 1 ]

7. 约瑟夫环问题

  1. 解法1。 使用链表 循环链表的解题思路比较简单,只需要将问题描述转换成代码即可。房间中的N个人组成一个长度为N的链表,首尾相接组成循环链表。列表中的每一项的值即为每个人的编号,在数到M时将该项(记为x)剔除,即该项的前一项的next不再指向x,而是x.next。依此规律遍历链表,直至链表中只剩下一项。
function createList(num) {
    //链表节点的数据结构
    function createNode(value) {
        return {
            value: value,
            next: ''
        }
    }
    //链表头节点
    let head = createNode(1);
    let node = head;
    //自头节点之后创建节点之间的关联关系
    for (let i = 2; i <= num; i++) {
        node.next = createNode(i);
        node = node.next;
    }
    //最后一个节点指向头节点,构成循环链表
    node.next = head;
    return head;
}
function deleteListNode(num, nth) {
    //创建数据长度为num的循环链表
    let node = createList(num);
    //链表长度>1时,继续下一轮
    while (num > 1) {
        for (let i = 1; i <= nth - 1; i++) {
            if (i == nth - 1) {
                //i为nth-1,则node.next即为第nth个节点。剔除node.next
                node.next = node.next.next;
                //链表长度--
                num--;
            }
            node = node.next;
        }
    }
    //剩余的最后一个节点的value值即为最后一人编号
    return node.value
}
deleteListNode(6, 4)
  1. 解法2: 使用递归
function JosephusR(num, nth) {
    let value = 0;
    for (let i = 1; i <= num; i++) {
        //此处为对i取余,上述递归中num也是在逐渐变小的,所以此处为i而非num
        value = (value + nth) % i;
    }

    return value + 1;
}
JosephusR(6, 4)

参考链接: www.jb51.net/article/222…

8. 最优方法 判断是否是质数

定义: 质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数(规定1既不是质数也不是合数)

// 最优方法 封装函数判断质数
export function isPrime(num) {
  // 1. 获取num的平凡根
  const temp = parseInt(Math.sqrt(num))

  // 2. 循环判断
  for (let i = 2; i <= temp; i++) {
    if (num % i === 0) {
      return false
    }
  }
  return true
}