数据结构和算法(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
}