1 Compreenda a complexidade do tempo
1.1 O que é complexidade de tempo?
A complexidade do tempo é uma função que descreve qualitativamente o tempo de execução do algoritmo. No desenvolvimento de software, a complexidade do tempo é usada para facilitar aos desenvolvedores estimar o tempo de execução do programa. O número de unidades operacionais do algoritmo é geralmente usado para representar o tempo consumido pelo programa. Aqui, por padrão, cada unidade da CPU leva o mesmo tempo para ser executada. Supondo que o tamanho do problema do algoritmo seja n
, então o número de unidades de operação é f(n)
representado por uma função. À medida que o tamanho dos dados n
aumenta, a taxa de crescimento do tempo de execução do algoritmo e f(n)
a taxa de crescimento mostram uma certa relação. Isso é chamado de assintótico complexidade de tempo do algoritmo. , referida como complexidade de tempo, denotada como O(f(n)
), onde n se refere ao número de conjuntos de instruções.
1.2 O que é grande O
Big O é usado para representar o limite superior do tempo de execução do algoritmo . Também pode ser entendido como o tempo de execução no pior caso. A quantidade e a ordem dos dados têm um grande impacto no tempo de execução do algoritmo. Supõe-se aqui, um determinado dado de entrada é usado. O tempo de execução deste algoritmo é maior que o tempo de cálculo de outros dados.
Todos dizemos que a complexidade de tempo da classificação por inserção é O(n^2)
, mas a complexidade de tempo da classificação por inserção tem uma ótima relação com os dados de entrada.Se os dados de entrada estiverem completamente ordenados, a complexidade de tempo da classificação por inserção é, se os dados de entrada O(n)
forem In ordem completamente inversa, a complexidade do tempo é O(n^2)
, então a O(n^2)
complexidade do tempo do pior caso é, dizemos que a complexidade do tempo da classificação por inserção é O(n^2)
.
A classificação rápida é O(nlogn)
que a complexidade de tempo da classificação rápida no pior caso é O(n^2)
, em geral O(nlogn)
, estritamente falando a partir da definição de grande O, a complexidade de tempo da classificação rápida deveria ser O(n^2) , mas ainda estamos dizendo que o a complexidade de tempo da classificação rápida é O(nlogn)
, esta é a regra padrão na indústria.
A complexidade de tempo da pesquisa binária é O(logn)
que o tamanho dos dados é reduzido pela metade a cada vez até que o tamanho dos dados seja reduzido para 1. Finalmente, é equivalente a encontrar a potência de 2 igual a n, o que equivale a dividi-la por vezes logn
.
A complexidade de tempo da classificação por mesclagem é O(nlogn)
, para fusão de cima para baixo, a complexidade de tempo é O (logn) quando a escala de dados é dividida de n para 1, e então a complexidade de tempo da fusão ascendente contínua é, e a complexidade de tempo geral O(n)
é O(nlogn)
.
A complexidade de travessia de uma árvore é geralmente O(n)
, n
que é o número de nós na árvore, e a complexidade temporal da classificação de seleção, que é O(n^2)
. Analisaremos gradualmente a complexidade de cada estrutura de dados e algoritmo nos capítulos correspondentes. Mais análises e derivações de complexidade de tempo podem ser encontradas no teorema principal.
1.3 Complexidade de tempo comum
1.3.1 O(1): complexidade constante
let n = 100;
1.3.2 O(logn): complexidade logarítmica
//二分查找非递归
var search = function (nums, target) {
let left = 0,
right = nums.length - 1;
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (nums[mid] === target) {
return mid;
} else if (target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
};
1.3.3 O(n): complexidade de tempo linear
for (let i = 1; i <= n; i++) {
console.log(i);
}
1.3.4 O(n^2): quadrado (loop aninhado)
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= n; j++) {
console.log(i);
}
}
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= 30; j++) {
//嵌套的第二层如果和n无关则不是O(n^2)
console.log(i);
}
}
1.3.5 O(2^n): complexidade exponencial
for (let i = 1; i <= Math.pow(2, n); i++) {
console.log(i);
}
1.3.6 O(n!): fatorial
for (let i = 1; i <= factorial(n); i++) {
console.log(i);
}
2 algoritmos de classificação comuns
2.1 Ordenação por seleção
Etapas do algoritmo:
Primeiro encontre o menor (maior) elemento na sequência não classificada e armazene-o no início da sequência classificada.
Em seguida, continue a encontrar o menor (maior) elemento entre os elementos não classificados restantes e coloque-o no final da sequência classificada.
Repita a segunda etapa até que todos os elementos estejam classificados.
A classificação por seleção é um algoritmo de classificação simples e intuitivo; não importa quais dados entrem, ele tem uma complexidade de tempo de O (n²). Portanto, quando for usado, quanto menor o tamanho dos dados, melhor. A única vantagem pode ser que não ocupa espaço adicional na memória.
function selectSort(arr) {
for (let i=0;i<arr.length-1;i++) {
let min = i;
for (let j=min+1;j<arr.length;j++) {
if (arr[min] > arr[j]) {
min = j;
}
}
let temp = arr[i];
arr[i] = arr[min]
arr[min] = temp;
}
return arr;
}
2.2 Classificação por bolhas
Compare elementos adjacentes. Se o primeiro for maior que o segundo, troque os dois;
A primeira passagem faz um loop 0-n para determinar o valor de n é encontrar o maior valor e borbulhar no topo
O segundo loop através de 0-n-1 determina o valor de n-1
A terceira passagem faz um loop 0-n-2 para determinar o valor de n-2
function bubleSort(arr) {
for (let i = 0;i<arr.length-1;i++) {
// 循环轮次
for (let j=0;j< arr.length-i-1;j++) {
// 每轮比较次数
if (arr[j] > arr[j+1]) {
// 相邻比较
let temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
}
return arr;
}
2.3 Ordenação por inserção
Os dois primeiros valores são classificados
Classifique os três primeiros valores no segundo ciclo, compare o último valor com o novo valor e insira-o na posição especificada
function insertSort(arr) {
for (let i = 1;i<arr.length;i++) {
// 循环轮次
let end = i;
let curr = arr[i]
while(end > 0 && curr < arr[end-1]) {
// 直到第一位 或者 当前的数不是最小值
arr[end] = arr[end - 1] // 移动比当前值小的值到后一位
end--
}
arr[end] = curr // 插入当前值
}
return arr;
}
2.4 Operação XOR
Um bit do resultado é 1 se e somente se esse bit for 1 em apenas uma das expressões. Caso contrário, o bit do resultado é 0, simplesmente ----- o mesmo é 0, a diferença é 1
Sintaxe: resultado = expressão1 ^ expressão2
按位异或 是对两个表达式执行 按位异或,先将两个数据转化为二进制数,然后进行 按位异或运算,只要位不同结果为 1,否则结果为 0
例如:
let a = 5;
let b = 8;
let c = a ^ b;
console.log(c) // 13
解析:
a 转二进制数为:0101
b 转二进制数为:1000
那么按照 按位异或 运算之后得到:1101(相同为 0,不同为 1),得到 c 的值就是 13
Características
1. Conheça a taxa de câmbio
a ^ b == b ^ a
2. A operação XOR de dois números idênticos deve resultar em 0
a^a === 0
3. 其他数字
O resultado obtido pela operação 0 e XOR deve ser其他数字
0^a === a
2.5 Exercícios
1. Dada uma matriz inteira não vazia, cada elemento aparece duas vezes, exceto um elemento que aparece apenas uma vez. Encontre o elemento que aparece apenas uma vez
let arr = [1, 3, 1, 2, 2, 7, 3, 6, 7]
// es5 解决方案
function fnc(arr){
let result = 0;
for(let i = 0; i < arr.length; i++){
result = result ^ arr[i];
}
return result;
}
// es6 解决方案
function fnc(arr){
return arr.reduce((a, b) => a ^ b, 0);
}