数据结构和算法

271 阅读3分钟

数据结构和算法(algorithm)

异或运算(相异为1)

异或运算的性质
  • 异或满足交换律结合律
  • 多个数异或顺序是无所谓的
  • 1 ^ 1 = 0
  • 1 ^ 0 = 1
  • 0 ^ N = N
  • N ^ N = 0

也可以理解为无进位相加

异或运算进行变量交换

采用这种方法有一个前提:a和b的内存地址不相同,如果相同执行完代码后,该位置的数为0

​
let a = 10    // 假如是x
let b = 20    // 假如是y
​
a = a ^ b     // a = x ^ y   b = y
b = a ^ b     // a = x ^ y   b = x ^ y ^ y = x ^ 0 = x
a = a ^ b     // a = x ^ y ^ x = 0 ^ y = y   b = x
// a = 20
// b = 10
异或面试题

有一个数组,里面只有一个数是出现奇数次,其他的都是出现偶数次,输出这个奇数次的数

function printOddTimesNum1(arr) {
    let eor = 0
    for (let i of arr) {  // 多个数异或的结果与顺序无关
        eor ^= i
    }
    console.log(eor)
}

有一个数组,里面有两个数是出现奇数次,其他都是出现偶数次,输出这两个数

function printOddTimesNum2(arr) {
    let eor = 0
    for (let i of arr) {
        eor ^= i   // 循环结束时,eor等于两个奇数次的数异或
    }
    const rightOne = eor & (~eor + 1)  // 提取出最右的1(其余位置为0),a和b两个数不相同的第一位
    let eor2 = 0
    for (let i of arr) {
        if ((rightOne & i) === 0) {
            eor2 ^= arr  // 循环结束后 eor2要么等于a,要么等于b(假设这两个数是a和b)
        }
    }
    console.log(eor2, or2 ^ eor)
}

选择排序

  • 时间复杂度 O(n^2)
function selectionSort(arr) {
    var minIndex, temp;
    for (var i = 0; i < arr.length - 1; i++) {
        minIndex = i;
        for (var j = i + 1; j < arr.length; j++) {
            if (arr[j] < arr[minIndex]) {     // 寻找最小的数
                minIndex = j;                 // 将最小数的索引保存
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;
}

冒泡排序

  • 时间复杂度 O(n^2)
function bubbleSort(arr) {
    for (var i = 0; i < arr.length - 1; i++) {
        for (var j = 0; j < arr.length - 1 - i; j++) {
            if (arr[j] > arr[j+1]) {        // 相邻元素两两对比
                var temp = arr[j+1];        // 元素交换
                arr[j+1] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr;
}

插入排序

  • 先让下标为0到1的数组有序,再让下标为0到2的数组有序,直到从0到arr.length-1有序

  • 比较过程中如果遇到前面没有数了,则该部分的数组有序

  • 比较过程中如果当前位置的数比前一个位置的数大,则该部分数组有序

  • 选择排序的时间复杂度和数据有关系

    • 最差情况:O(n^2),时间复杂度是按最差情况的
    • 最好情况:O(n)
function insertSort(arr) {
    for (let i = 1; i < arr.length; i++) {
        for (let k = i; k > 0 && arr[k] <= arr[k - 1]; k--) {
                arr[k] = arr[k] ^ arr[k - 1];
                arr[k - 1] = arr[k] ^ arr[k + 1];
                arr[k] = arr[k] ^ arr[k + 1];
        }
    }
}

二分法(BinarySearch

  • 在一个有序数组中,找一个数是否存在
function binarySearch(arr, num) {
    let lowIndex = 0
    let highIndex = arr.length - 1
    
    while(lowIndex <= highIndex) {
        // 在数组的长度特别大时,取中点,lowIndex + highIndex可能会发生溢出
        // lowIndex + (highIndex - lowIndex) >> 1, 取中点可以这样取
        const middleIndex = Math.ceil((lowIndex + highIndex) / 2)
        
        if (num > arr[middleIndex]) {
            lowIndex = middleIndex + 1
        } else if (num < arr[middleIndex]) {
            highIndex = middleIndex - 1
        } else {
            return middleIndex
        }
    }
    
    return -1
}

归并排序(MergeSort)

将一个数组分成两个数组,将这两个数组分别进行排序(递归) ,排完序后,用两个指针分别指向两个数组的第一位,判断大小,谁小谁放到一个新数组中,指针右移,当有一个指针右移溢出时,直接将另一部分的数组放到新数组即可,最后将新数组赋值给一开始的数组。

function mergeSort(arr) {
    if (arr.length < 2) return arr
    const mid = Math.floor(arr.length)
    const left = arr.slice(0, mid)
    const right = arr.slice(mid)
    return merge(mergeSort(left), mergeSort(right))
}
function merge(left, right) {
    const arr = []
    let p1 = 0
    let p2 = 0
    
    while (p1 < left.length && p2< right.length) {
        arr.push(left[p1] <= right[p2] ? left[p1++] : right[p2++])
    }
    while (p1 < left.length) {
        arr.push(left[p1++])
    }
    while (p2 < right.length) {
        arr.push(right[p2++])
    }
    return arr
}