Arrays, Linked Lists e Jump Lists de Estruturas de Dados - Notas Introdutórias sobre Algoritmos e Estruturas de Dados (3)

logotipo CSDNPublicar

Este artigo é a terceira parte das notas de estudo sobre algoritmos e estruturas de dados e será atualizado continuamente. Amigos são bem-vindos para ler e aprender. Se há algo que eu não entendo ou está errado, por favor comunique

estrutura de dados

Uma estrutura de dados refere-se a uma coleção de elementos de dados que têm um ou mais relacionamentos específicos entre si. Diferentes estruturas de dados geralmente trazem diferentes eficiências de processamento em diferentes cenários de aplicativos. Esta nota apresentará e explicará teoricamente as oito estruturas de dados a seguir por meio de diagramas, para que todos possam dominar a estrutura de dados.
Adicione uma descrição da imagem

Classificação de Estruturas de Dados

A estrutura de dados pode ser classificada de acordo com a estrutura lógica e a estrutura física.

A estrutura lógica é um modelo abstraído de problemas específicos, e é uma estrutura em sentido abstrato, expressando o relacionamento entre elementos de dados em objetos. Estruturas lógicas comuns incluem estruturas lineares e estruturas não lineares (estruturas de conjunto, estruturas de árvore, estruturas de gráfico).

  • Estruturas lineares, incluindo arrays, listas encadeadas, pilhas e filas , onde há uma relação um-para-um entre os elementos de dados;
  • Estruturas de coleção, incluindo heaps e tabelas de hash, onde os elementos de dados não têm nenhum relacionamento além de pertencer à mesma coleção;
  • Uma estrutura de árvore, como uma árvore, na qual há um relacionamento hierárquico de um para muitos entre os elementos de dados;
  • Uma estrutura de gráfico, conforme mostrado na figura, na qual os elementos de dados estão em um relacionamento muitos-para-muitos.

A estrutura física , também conhecida como estrutura de armazenamento , é a representação real da estrutura lógica no computador. Estruturas físicas comuns incluem estrutura de armazenamento sequencial e estrutura de armazenamento em cadeia , que representam a estrutura de memória; estrutura de armazenamento de índice e estrutura de armazenamento de hash , que representam a estrutura de interação entre a memória externa e a memória.

  • Estruturas de armazenamento sequencial, incluindo arrays, colocam elementos de dados em unidades de armazenamento com endereços contínuos, e as relações lógicas e físicas entre os dados são consistentes
  • Estruturas de armazenamento vinculadas, incluindo listas vinculadas, árvores e gráficos, armazenam elementos de dados em unidades de armazenamento arbitrárias. Esse grupo de unidades de armazenamento pode ser contínuo ou descontínuo, portanto, o relacionamento físico entre os elementos de dados não pode refletir os elementos de dados. O relacionamento lógico entre eles, um ponteiro é introduzido na estrutura de armazenamento vinculada para armazenar as informações de endereço de elementos adjacentes.
  • Estrutura de armazenamento de índice: além de estabelecer as informações do nó de armazenamento, uma tabela de índice adicional também é estabelecida para identificar o endereço do nó. Uma tabela de índice consiste em várias entradas de índice.
  • Estrutura de armazenamento de hash: também conhecido como armazenamento de hash, o endereço de armazenamento do nó é determinado pelo valor do código-chave do nó.

variedade

Uma matriz é uma estrutura de dados de tabela linear que usa um conjunto de espaços de memória contínuos para armazenar um conjunto de dados do mesmo tipo. Pode-se dizer que é a estrutura de dados mais básica.
Adicione uma descrição da imagem
Conforme mostrado na figura acima, os dados são armazenados sequencialmente no espaço contínuo da memória, 0, 1, 2, ... tipo de dados de matriz, de modo que cada endereço de memória dos dados (a localização na memória) pode ser calculado por meio do subscrito de matriz, para que os dados de destino possam ser acessados ​​diretamente para atingir o objetivo de acesso aleatório . De acordo com o tipo de elementos de dados, as matrizes podem ser divididas em matrizes de inteiros, matrizes de caracteres, matrizes de ponto flutuante, matrizes de ponteiros e matrizes de estrutura. Os arrays também podem ter representações unidimensionais, bidimensionais e multidimensionais.

vantagem

  1. A velocidade de consulta de elementos por índice é muito rápida;
  2. Iterar sobre uma matriz por índice também é útil.

deficiência

  1. O tamanho do array é determinado após a criação e não pode ser expandido;
  2. As matrizes podem armazenar apenas um tipo de dados;
  3. A operação de inserção e exclusão de elementos é ineficiente.

Por que os arrays começam a numerar de 0 em vez de 1?

Do ponto de vista do modelo da matriz, a definição mais precisa de "subscrito" deve ser "deslocamento". Ou seja, se for ausado para representar um array, a[0]significa a posição com offset 0, ou seja, o primeiro endereço, e a[k]significa a posição com offset k type_size, então o cálculo a[k]do endereço de memória só precisa usar a seguinte fórmula :  

a[k]_address = base_address + k * type_size

Se a numeração começar em 1, o cálculo do endereço de memória a[k] do será:
  
a[k]_address = base_address + (k-1) * type_size

Comparado com as duas fórmulas acima, a numeração começa em 1, e cada acesso aleatório aos elementos do array requer uma operação de subtração. otimiza a eficiência. Faça-o o maior possível. Portanto, para economizar uma operação de subtração, a matriz escolhe começar a numerar de 0 em vez de 1.

Por que a inserção/exclusão de um array seria ineficiente?

Como os dados na matriz são ordenados, se inserirmos um novo elemento em uma determinada posição, devemos mover os seguintes dados, o melhor caso é Ω ( 1 ) \Omega(1)Ω ( 1 ) , pior casoO ( N ) O(N)O ( N ) , porque temos a mesma probabilidade de inserir um elemento em cada posição, então a complexidade de tempo média do caso é( 1 + 2 + ⋅ ⋅ ⋅ + n ) / n = Θ ( n ) (1+2+\ cdot \cdot\cdot+n)/n = \Theta(n)( 1+2++n ) / n=Θ ( n ) .

linguagem C

Na linguagem C, array é um tipo de dado básico, e um array pode ser criado declarando uma variável de array. Você pode usar subscritos para acessar elementos em uma matriz. Aqui está um código de amostra simples:

int arr[10]; // 声明一个包含10个元素的整型数组
arr[0] = 1; // 给第一个元素赋值为1

lista encadeada

Uma lista encadeada é uma estrutura de dados na qual os elementos de dados são armazenados em uma estrutura de armazenamento encadeada.Esta estrutura de armazenamento tem as características de descontinuidade física. A lista encadeada é composta por uma série de nós de dados e cada nó de dados inclui duas partes: campo de dados e campo de ponteiro. Entre eles, o campo de ponteiro salva o endereço onde o próximo elemento na estrutura de dados está armazenado.

Adicione uma descrição da imagem
A figura acima mostra uma lista encadeada unidirecional comum com um cabeçalho e um final Adicionar um campo de ponteiro de link reverso ou um cabeçalho e final de link também pode formar uma lista duplamente vinculada ou uma lista vinculada circular unidirecional .

Como o próximo elemento de dados é pesquisado e acessado por meio do ponteiro, a lista encadeada possui um maior grau de liberdade. Isso mostra que, ao adicionar e excluir nós, apenas o endereço do ponteiro do nó anterior precisa ser modificado sem alterar outros nós. No entanto, tudo tem dois extremos: embora os ponteiros tragam um alto grau de liberdade, eles sacrificarão naturalmente a eficiência da pesquisa de dados e o uso do espaço extra.

vantagem

  1. Vários tipos de dados podem ser definidos em um nó
  2. As operações de inserção e exclusão são mais eficientes

deficiência

A eficiência de acesso é baixa.

nó de cabeça, ponteiro de cabeça e nó de cabeça

Na verdade, a estrutura da lista encadeada mostrada na figura acima não está completa. Uma lista encadeada completa precisa ser composta das seguintes partes: 1. Ponteiro de cabeça: um ponteiro comum, que se caracteriza por apontar sempre para o primeiro nó da lista encadeada. Obviamente, o ponteiro de cabeçalho é usado para indicar a localização da lista encadeada, de modo que é conveniente encontrar a lista encadeada e usar os dados da tabela posteriormente; 2. Nó: os nós da lista encadeada são subdivididos em nó de cabeça , nó principal e outros nós: Nó principal: na verdade, um nó vazio que não armazena nenhum dado, geralmente como o primeiro nó da lista encadeada. Para a lista encadeada, o nó de cabeça não é necessário, sua função é apenas para a conveniência de resolver alguns problemas práticos; nó de cabeça: por causa do nó de cabeça (ou seja, o nó vazio), é chamado de primeiro nó na lista vinculada que possui dados é o nó principal. O nó principal é apenas um título para o primeiro nó de dados na lista encadeada, que não tem significado prático; outros nós: outros nós na lista encadeada;

Portanto, uma estrutura de lista encadeada completa armazenando {1,2,3} é mostrada na figura a seguir:
Adicione uma descrição da imagem

Observação: quando houver um nó de cabeçalho na lista vinculada, o ponteiro de cabeçalho apontará para o nó de cabeçalho; caso contrário, se não houver nenhum nó de cabeçalho na lista vinculada, o ponteiro de cabeçalho apontará para o nó de cabeçalho.

linguagem C

A implementação específica de cada nó na lista encadeada precisa usar a estrutura em linguagem C, e o código de implementação específico é:

typedef struct Linklist{
    int  elem;//代表数据域
    struct Linklist *next;//代表指针域,指向直接后继元素
}Linklist; //link为节点名,每个节点都是一个 link 结构体

Geralmente, usamos typedef struct para criar listas vinculadas, porque quando definimos variáveis ​​de estrutura dessa maneira, podemos usar LinkList *a; diretamente para definir variáveis ​​de tipo de estrutura.

Criar uma lista encadeada requer o seguinte trabalho: 1. Declarar um ponteiro de cabeçalho (se necessário, você pode declarar um nó de cabeçalho); 2. Criar vários nós que armazenam dados e estabelecer um relacionamento lógico com seus nós predecessores a qualquer momento durante a processo de criação;

Por exemplo, para criar uma lista encadeada que armazena {1,2,3,4} e não possui nós principais, o código de implementação da linguagem C é o seguinte:

linklist * initlinklist(){
    linklist * p=NULL;//创建头指针
    linklist * temp = (linklist*)malloc(sizeof(linklist));//创建首元节点
    //首元节点先初始化
    temp->elem = 1;
    temp->next = NULL;
    p = temp;//头指针指向首元节点
    //从第二个节点开始创建
    for (int i=2; i<5; i++) {
     //创建一个新节点并初始化
        linklist *a=(linklist*)malloc(sizeof(linklist));
        a->elem=i;
        a->next=NULL;
        //将temp节点与新建立的a节点建立逻辑关系
        temp->next=a;
        //指针temp每次都指向新链表的最后一个节点,其实就是 a节点,这里写temp=a也对
        temp=temp->next;
    }
    //返回建立的节点,只返回头指针 p即可,通过头指针即可找到整个链表
    return p;
}

A adição de elementos à lista vinculada pode ser dividida nas três situações a seguir, de acordo com as diferentes posições de adição: 1. Inserir no cabeçalho da lista vinculada (após o nó principal) como o nó principal; 2. Inserir em uma determinada posição na no meio da lista encadeada 3. Inserir no final da lista encadeada como o último elemento de dados na lista encadeada;

Embora a posição de inserção do novo elemento não seja fixa, a ideia de inserir elementos na lista encadeada é fixa. Você só precisa seguir os dois passos a seguir para inserir o novo elemento na posição especificada: 1. Aponte o próximo ponteiro do novo nó para a posição de inserção 2. Aponte o próximo ponteiro do nó antes da posição de inserção para o nó de inserção.

O código em linguagem C para implementar a operação de inserção de elementos na lista encadeada é o seguinte:

//p为原链表,elem表示新数据元素,add表示新元素要插入的位置
linklist * insertElem(linklist * p,int elem,int add){
    linklist * temp=p;//创建临时结点temp
    //首先找到要插入位置的上一个结点
    for (int i=1; i<add; i++) {
        if (temp==NULL) {
            printf("插入位置无效\n");
            return p;
        }	//判断用户输入的插入位置是否有效
        temp=temp->next;
    }   
    //创建插入结点c
    linklist * c=(linklist*)malloc(sizeof(linklist));
    c->elem=elem;
    //向链表中插入结点
    c->next=temp->next;
    temp->next=c;
    return  p;
}

Excluir um elemento de dados especificado da lista vinculada é, na verdade, remover o nó que armazena o elemento de dados da lista vinculada, mas como um programador qualificado, você deve ser responsável pelo espaço de armazenamento e liberar o espaço de armazenamento não mais usado a tempo. Portanto, excluir elementos de dados da lista vinculada requer as duas etapas a seguir: 1. Remova o nó da lista vinculada; 2. Libere manualmente o nó e recupere o espaço de armazenamento ocupado pelo nó;

Entre eles, a implementação de remover um nó da lista encadeada é muito simples, basta encontrar a temperatura do nó predecessor direto do nó e executar um programa de uma linha:

temp->next=temp->next->next;

Portanto, a implementação da linguagem C para excluir elementos de uma lista encadeada é a seguinte:

//p为原链表,add为要删除元素的值
linklist * delElem(linklist * p,int add){
    linklist * temp=p;
    //temp指向被删除结点的上一个结点
    for (int i=1; i<add; i++) {
        temp=temp->next;
    }
    linklist * del=temp->next;//单独设置一个指针指向被删除结点,以防丢失
    temp->next=temp->next->next;//删除某个结点的方法就是更改前一个结点的指针域
    free(del);//手动释放该结点,防止内存泄漏
    return p;
}

Podemos ver que o nó del removido da lista encadeada é finalmente liberado manualmente por meio da função free.

O método mais comumente usado para encontrar um elemento de dados especificado em uma lista vinculada é percorrer os nós da lista sequencialmente a partir do início da lista e comparar o elemento pesquisado com o elemento de dados armazenado no campo de dados de cada nó até que o a comparação é bem-sucedida ou percorre até o final da lista

Portanto, o código de implementação da linguagem C para localizar um elemento de dados específico na lista vinculada é:

//p为原链表,elem表示被查找元素、
int selectElem(linklist * p,int elem){
//新建一个指针t,初始化为头指针 p
    linklist * t=p;
    int i=1;
    //由于头节点的存在,因此while中的判断为t->next
    while (t->next) {
        t=t->next;
        if (t->elem==elem) {
            return i;
        }
        i++;
    }
    //程序执行至此处,表示查找失败
    return -1;
}

Nota: Ao percorrer uma lista vinculada com um nó principal, é necessário evitar a influência do nó principal nos dados de teste. Portanto, ao percorrer a lista vinculada, estabeleça e use o método de passagem no código acima e ignore diretamente o nó principal para efetivamente percorrer a lista encadeada.

Para atualizar um elemento na lista vinculada , você só precisa encontrar o nó que armazena o elemento percorrendo e alterando o campo de dados no nó. Forneça diretamente o código de implementação da linguagem C para atualizar os elementos de dados na lista vinculada:

//更新函数,其中,add 表示更改结点在链表中的位置,newElem 为新的数据域的值
linklist *amendElem(linklist * p,int add,int newElem){
    linklist * temp=p;
    temp=temp->next;//在遍历之前,temp指向首元结点
    //遍历到被删除结点
    for (int i=1; i<add; i++) {
        temp=temp->next;
    }
    temp->elem=newElem;
    return p;
}

pular tabela*

A tabela de salto é uma estrutura de dados mágica, porque quase todas as versões dos livros didáticos de graduação não possuem a estrutura de dados da tabela de salto e não é apresentada nos dois livros "Introdução aos Algoritmos" e "Algoritmos Quarta Edição". No entanto, a complexidade de tempo de inserção, exclusão e localização de elementos na tabela de salto é a mesma da árvore rubro-negra, e a complexidade de tempo é O ( log ⁡ n ) O(\log n)O ( lo gn ) , e a implementação da tabela de salto é mais simples do que a da árvore rubro-negra. Em um ambiente simultâneo, a operação da tabela de salto é mais localizada e o desempenho da tabela de salto é melhor. Portanto, na indústria, as tabelas de salto são frequentemente usadas.

Embora a lista encadeada melhore o grau de liberdade adicionando campos de ponteiro, ela leva à deterioração da eficiência da consulta de dados. Especialmente quando o comprimento da lista vinculada é muito longo, a consulta dos dados deve ser feita desde o início, o que será menos eficiente. A geração da tabela de salto é para resolver o problema da lista encadeada muito longa. Ao aumentar o índice multinível da lista encadeada para acelerar a eficiência da consulta da lista encadeada original, conforme mostrado na figura abaixo. Como mostrado em Na figura acima, a tabela de salto adiciona vários níveis à
Adicione uma descrição da imagem
lista encadeada ordenada original Índice, o índice primário é n / 2 n/2n /2 , o índice secundário én/4 n/4n /4 , o índice terciário én/8 n/8n /8 , ···Ao extrair o índice para cima, a eficiência da busca é aumentada.Na verdade, este também é um algoritmo "espaço por tempo". Portanto, a lista de salto é essencialmente umalista encadeada ordenada que pode realizar pesquisa binária.

característica

  1. A essência da lista de atalhos é uma lista encadeada ordenada de várias camadas, que combina as ideias de listas binárias e encadeadas;
  2. Cada nó da lista de atalhos contém dois ponteiros, um apontando para o próximo elemento na mesma lista encadeada e outro apontando para o elemento da próxima camada;
  3. Se um elemento aparecer na lista encadeada no nível i, ele também aparecerá nas listas encadeadas abaixo do nível i;
  4. A lista encadeada mais baixa contém todos os elementos;
  5. A complexidade de tempo da consulta, inserção e exclusão da tabela de salto é O ( log ⁡ n ) O(\log n)O ( lo gn ) _

Análise de Complexidade de Tempo da Skip List

A complexidade de tempo da consulta em uma lista encadeada individualmente é O (n) O(n)O ( n ) , agora analise que existemnnQuantos níveis de índices existem para n nós?

De acordo com cada dois nós, um nó é extraído como o nó do índice de nível superior, então o nó do índice de primeiro nível é sobre n / 2 n/2n /2 deles, o índice do segundo nível é de cerca den/4 n/4n /4 , e assim por diante, então okkthO número de pontos de índice de nível k :n / 2 kn/2{^{k}}n /2k .

Suponha que o índice tenha hhNível h , o índice mais alto é de 2 nós, através do exemplo acima pode ser obtido: n 2 h = 2 \frac{n}{2^h}=22hn=2 Encontre:h = log ⁡ 2 n − 1 h=\log_2n-1h=pouco tempo2n1 . Se a camada da lista vinculada original estiver incluída, a altura de toda a lista de pular será:log ⁡ 2 n \log_2npouco tempo2n .

Quando consultamos certos dados na tabela de salto, se cada camada tiver que percorrer mmm nós, a complexidade de tempo de consulta de dados na tabela de salto é:O ( m ∗ log ⁡ n ) O(m*\log n)O ( mpouco tempon )milímetrosQual é o valor de m ?

Suponha que os dados que estamos procurando sejam xxx , ok-ésimoNo índice de nível k , percorremos parayyApós o nó y , encontre que x > y, x < zx > y, x < zx>y , x<z , então passeyyO ponteiro para baixo de y , dokkthíndice de nível k parak − 1 k - 1kÍndice de nível 1 . emk − 1 k - 1kNo índice de nível 1 , aay somazzEncontre outro nó entre z , então nós k − 1 k - 1kNo índice de primeiro nível, no máximo 3 nós são percorridos, e assim por diante, cada nível de índice só precisa percorrer no máximo 3 nós.

Através da análise acima, obtemos mmO valor de m é 3. Os coeficientes são ignorados, portanto, a complexidade de tempo de procurar quaisquer dados na tabela de salto éO ( log ⁡ n ) O(\log n)O ( lo gn ) , a complexidade de tempo da pesquisa é a mesma da pesquisa binária.

Análise de Complexidade Espacial de Skip List

A tabela de salto estabelece muitos níveis de índices para melhorar a eficiência de encontrar elementos, que é uma ideia típica de "espaço por tempo", então alguns sacrifícios são feitos no espaço, então qual é a complexidade do espaço?

Se a lista encadeada original contiver nnn elementos, o número de elementos de índice primário én / 2 n/2n /2 , o número de elementos de índice secundário én / 4 n/4n /4 , o número de elementos de índice de terceiro nível én / 8 n/8n /8 ... Portanto, a soma dos inodes é:n / 2 + n / 4 + n / 8 + ... + 8 + 4 + 2 = n − 2 n/2 + n/4 + n/8 + ... + 8 + 4 + 2 = n-2n /2+n /4+n /8++8+4+2=n2 , a complexidade do espaço éO ( n ) O(n)O ( n ) _

Inserção e exclusão de tabela de salto

Inserir dados também parece muito simples, a lista encadeada original da lista de atalhos precisa ser mantida em ordem, assim encontraremos a posição onde o elemento deve ser inserido, como se estivéssemos procurando um elemento. Portanto, a complexidade de tempo geral da inserção é a complexidade de tempo de encontrar elementos O (logn) O(logn)O ( log n ) mais a complexidade de tempo de inserir elementos em uma lista encadeada individualmente é O ( 1 ) O (1)O ( 1 ) , no final, a complexidade de tempo éO(logn) O(logn)O ( l o g n ) _

Na operação delete, além de deletar os nós da lista encadeada original, também precisamos deletar os pontos do índice.

Qual é a complexidade de tempo de excluir elementos na lista de pular?

O processo de exclusão de um elemento é semelhante ao processo de localização de um elemento, exceto que se o elemento x a ser excluído for encontrado no caminho de pesquisa, a operação de exclusão será executada. Na lista de atalhos, cada camada de índice é, na verdade, uma lista ordenada de encadeamento simples, e a complexidade de tempo para excluir elementos na lista de encadeamento simples é O (1) O(1)O ( 1 ) , o número de camadas de índice élog ⁡ n \log npouco tempon indica que no máximolog ⁡ n \log npouco tempon elementos, então o tempo total para excluir um elemento inclui o tempo para encontrar um elemento mais excluirlog ⁡ n \log npouco tempoO tempo para n elementos é O ( log ⁡ n ) + O ( log ⁡ n ) = 2 O ( log ⁡ n ) O(\log n) + O(\log n) = 2 O(\log n)O ( lo gn )+O ( lo gn )=2 O ( lo gn ) , ignorando a parte constante, a complexidade de tempo de deletar elementos éO ( log ⁡ n ) O(\log n)O ( lo gn ) _

Atualização dinâmica da tabela de saltos

Se continuarmos inserindo elementos na lista de saltos, isso pode causar muitos nós entre os dois pontos de índice. Se houver muitos nós, perderemos a vantagem de construir um índice. Portanto, precisamos manter o equilíbrio entre o tamanho do índice e a lista encadeada original, ou seja, o número de nós aumenta e o índice aumenta de acordo, para evitar a situação de muitos nós entre os dois índices e a diminuição da eficiência de busca.

A tabela de salto mantém esse equilíbrio por meio de uma função aleatória . Quando inserimos dados na tabela de salto, podemos optar por inserir os dados no índice ao mesmo tempo. Então, em qual nível de índice inserimos, isso é Uma função aleatória é necessários para determinar em qual nível de índice inserimos.

Por exemplo, toda vez que um novo elemento for inserido, tente deixar o elemento ter uma probabilidade de 1/2 para estabelecer um índice de primeiro nível, uma probabilidade de 1/4 para estabelecer um índice de segundo nível, uma probabilidade de 1/ 8 para estabelecer um índice de terceiro nível, e assim por diante. Desta forma, a tabela de salto pode ser efetivamente impedida de degradar, resultando em baixa eficiência.

linguagem C

A implementação da linguagem C da tabela de salto pode se referir à tabela de salto de design [LeetCode.1206] e https://blog.csdn.net/pcj_888/article/details/110723507 .

resumo

As semelhanças e diferenças entre arrays, listas vinculadas e listas de salto também são um dos pontos de inspeção de alta frequência nas entrevistas. A seguir está uma tabela comparando arrays, listas encadeadas e listas de salto, na esperança de ajudá-lo a entender melhor as diferenças e conexões entre eles:

método de armazenamento Comprimento dos dados operação de inserir/excluir operação de acesso
variedade espaço de memória contíguo O comprimento é fixo, geralmente não expansível dinamicamente O (n) / O (n) O(n) / O(n)O ( n ) / O ( n ) Acesso aleatório O (1) O(1)O ( 1 )
lista encadeada Espaço de memória não contíguo, conectando nós por meio de ponteiros O comprimento pode ser alterado dinamicamente O ( 1 ) / O ( 1 ) O(1) / O(1) O(1)/O(1) acesso sequencial O (n) O(n)O ( n )
mesa de salto Estrutura de índice multinível, semelhante a uma árvore balanceada O comprimento pode ser alterado dinamicamente e é necessário espaço adicional para armazenar o índice O ( log ⁡ n ) / O ( log ⁡ n ) O(\log n) / O(\log n)O ( lo gn ) / O ( log gn ) Acesso rápido O ( log ⁡ n ) O(\log n)O ( lo gn )

Acho que você gosta

Origin blog.csdn.net/a2360051431/article/details/130798450
Recomendado
Clasificación