Tabla lineal de estructura de datos de posgrado

El concepto básico y la realización de la tabla lineal.

1. Definición de tabla lineal

Una tabla lineal es una secuencia finita de elementos de datos con las mismas características .

El número de elementos se denomina longitud de la tabla lineal, n (n> = 0) significa, n = 0 (tabla vacía)

2. Características lógicas de tablas lineales.

Solo hay un elemento de encabezado y solo un elemento de cola. No hay predecesor en el encabezado ni sucesor en la cola. Excepto el encabezado y el pie de página, los otros elementos tienen un solo precursor directo y un solo sucesor directo.

3. Estructura de almacenamiento de la mesa lineal.

Hay dos tipos de estructura de almacenamiento secuencial (lista de secuencias) y estructura de almacenamiento en cadena (lista vinculada).

Tabla de secuencia

Almacenamiento continuo, almacenamiento secuencial.

Lista vinculada

No solo la información de los elementos, sino también la información de la relación lógica (la información de dirección de los nodos posteriores).

Comparación de dos estructuras de almacenamiento.

Tabla de secuencia:

Función de acceso aleatorio, que ocupa espacio de almacenamiento continuo.

Insertar: Necesidad de mover múltiples elementos.

Lista vinculada

No se admite el acceso aleatorio, la tasa de utilización del espacio de almacenamiento es ligeramente inferior a la tabla de secuencia y se admite la asignación dinámica del espacio de almacenamiento.

Insertar: no es necesario mover elementos.

Cinco formas de listas vinculadas:

  1. Lista vinculada individualmente:

    Lista enlazada individual con nodo principal (no hay información almacenada en el nodo principal): cabeza-> siguiente == Nulo, la lista vinculada está vacía.

    Lista vinculada individualmente sin encabezado: head == Nulo, la lista vinculada está vacía.

  2. Lista doblemente vinculada: un nodo precursor más

  3. Lista circular individualmente vinculada:

    El último campo de puntero (puntero nulo) de la lista vinculada individualmente apunta al primer nodo. Si el nodo de bucle usa un nodo principal, el último campo de puntero (puntero nulo) apunta al nodo principal.

  4. Lista circular de doble enlace:

    head == Null, la lista circular de doble enlace sin nodo head está vacía.

    El nodo inicial, en estado vacío, head-> next y head-> prior debe ser igual a head.

    Cualquiera de las siguientes cuatro oraciones puede ser verdadera para determinar que la lista circular doblemente enlazada está vacía.

    head->next==head;
    head->priot==head;
    head->next==head && head->priot==head;
    head->next==head || head->priot==head;
    
  5. Lista enlazada estática

    El puntero indica la dirección del siguiente elemento en la lista vinculada en la matriz.

    En comparación con la tabla de secuencia, la ventaja es que es fácil de insertar y eliminar.

Nota: La comparación de la tabla de secuencia y la lista vinculada a menudo se toma en el examen de posgrado, y se da una respuesta integral.

Comparación basada en el espacio

  1. Distribución de métodos de almacenamiento:

    El espacio de almacenamiento de la tabla de secuencia se asigna una vez, y el espacio de almacenamiento de la lista vinculada se asigna varias veces.

  2. Densidad de almacenamiento (densidad de almacenamiento = cantidad de almacenamiento ocupada por el dominio de valor del nodo / cantidad de almacenamiento total ocupada por la estructura del nodo)

    La densidad de almacenamiento de la tabla de secuencia = 1 y la densidad de almacenamiento de la lista vinculada <1 (porque hay un campo de puntero en el nodo)

Comparación basada en el tiempo

  1. Método de acceso

    Se puede acceder aleatoriamente a la tabla de secuencia;

    Solo se puede acceder a la lista vinculada secuencialmente (atravesando el elemento anterior)

  2. Número de elementos para mover al insertar / eliminar:

    La tabla de secuencia necesita mover casi la mitad de los elementos en promedio;

    La lista vinculada no necesita mover elementos, solo se necesita cambiar el puntero.

N tabla de secuencia y eliminar elementos insertados y análisis de complejidad se aplica:

  • Encuentra la probabilidad

    Posiciones de inserción aleatorias, n posiciones de inserción, probabilidad de inserción en cualquier posición p = 1 / n

  • El número de elementos que deben moverse en la posición correspondiente.

    Después de insertar el elemento i-ésimo, mueva el elemento ni.

  • Expectativa matemática E de elementos móviles:

    E = p (n + (n-1) + (n-2) + …… + 0) = (n-1) / 2; O (n)

    2.2 Definición de estructura y funcionamiento básico de la tabla lineal.

    Definición de estructura de tabla lineal

    #define maxSize 100
    

    1. Definición de estructura de la tabla de secuencia

    typedef struct{
        int data[maxSize];
        int length;
    }Sqlist;
    

    Nota: La definición de la tabla más lineal utilizada en el examen es la siguiente forma (por simplicidad):

    int A[maxSize];
    int n;//长度为n
    

    2. Definición de nodos de lista enlazados individualmente

    estructura typedef LNode{
    datos int;
    struct LNode * next;
    }LNode;

    Recomiende esto Las líneas amarillas son tan buenas como las escritas.

    3. Definición de lista doblemente vinculada

    typedef struct LNode{
    	int data;
    	struct LNode* prior;
    	struct LNode* next;
    }LNode;
    

    Nota: Al asignar el espacio de un nodo de lista vinculada, defina un puntero que apunte al nodo. El nombre de este puntero se usa a menudo como el nombre del nodo.

    LNode *A = (LNode*)malloc(sizeof(LNode))

    int p = (int)malloc(sizeof(int))

    typedef struct node{
        int x;
        int y;
    }node;
    int p = (int)malloc(sizeof(int));//ok
    node n = (node)malloc(sizeof(node));//不ok
    node no = new node;//不ok
    node *No = new node[5];//ok
    //上述几个不ok得原因没有想通。
    

    La diferencia entre '*' y '->':

    componente variable de estructura tomada por ''.

    LNode a;
    a.data;
    

    El puntero a la variable de estructura toma el componente con '->'

    LNode *b;
    b->data;
    //(*b)就变成了结构体变量可以用'.'
    (*b).data;
    

    Descripción y explicación:

    "P apunta a q", p se refiere a un puntero, porque p es tanto un nombre de puntero como un nombre de nodo,Pero el nodo no puede apuntar al nodo, Entonces p se refiere al puntero. Otro ejemplo es "utilizar la función free () para liberar el espacio de p". En este momento, p se refiere al nodo, porque p es un nombre de puntero y un nombre de nodo , pero el sistema asigna el espacio de almacenamiento requerido por la variable de puntero en sí mismo sin requerir que el usuario llame a la función free()Liberación, solo el espacio de almacenamiento asignado por el usuario debe ser liberado por el usuario, por lo que p se refiere al nodo.

    Suplemento: (Solo para suplemento, para facilitar una comprensión más profunda).

    Algunos compañeros de clase pueden tener las mismas dudas que yo. Este LNode, en la función principal, no lo declaro como un puntero LNode *, debo intentar declararlo como LNode;

    Nuestra conclusión a través del código es:De hecho, el nodo no puede apuntar al nodo, Debido a que el siguiente atributo en Lnode es un puntero, solo podemos permitir que el puntero de LNode * apunte a LNode * next (¡la práctica lo sabe!);

    #include <iostream>
    #include<stdlib.h> 
    using namespace std;
    typedef struct LNode{
        int data;
        struct LNode* next;
    }LNode;
    void creat_LNode(LNode &L);
    void print(LNode L);
    int  main() {
        LNode L;
        creat_LNode(L);
        print(L);
        return 0;
    }
    void creat_LNode(LNode &L){
        LNode *temp = &L;
        for(int i =0;i<10;i++){
            temp->data = i;
            LNode* temp2 = (LNode*)malloc(sizeof(sizeof(LNode)));
            temp->next = temp2;
            temp = temp2;
        }
        temp->next = NULL;
        //free(temp);此处不能free();
    }
    void print(LNode L){
        LNode *temp = &L;
        while(temp->next!=NULL){
            cout<<temp->data<<" ";
            temp = temp->next;
        }
    }
    

    Inicialización de la tabla de secuencia:

    void initList(Sqlist &L){
    	L.length = 0;
    }
    

    "Análisis de cotizaciones y":

    Inserción de la tabla de secuencia: después de insertar e en la posición p, p devuelve 0 incorrectamente.

    void insertElem(Sqlist &L,int p,int e);

    '&' Es una cita, no lo entiendo como una dirección, Debido a que L debe cambiarse, use una referencia para recuperar el valor modificado. Si no necesita cotizar, el valor modificado en la función no se puede recuperar.

    //p的检查
    if(p<0 || p>L.length || L.length == maxSize)
        return 0;
    

    Inserción de lista vinculada:

    Inserción de cola vinculada x

    void insertElem(LNode *L,int x)

    Hemos modificado la lista L individualmente vinculada, pero no es útil.&L

    void insertElem(LNode* &L,int x);

    El cambio de datos internos L no tiene nada que ver con == & ==.

    Se agrega una referencia para permitir que se modifique el puntero L y luego se lo devuelve a la función principal.

    Si no se agrega ninguna referencia, incluso si insertamos la función y dejamos que L vuelva a apuntar a un nuevo puntero, el valor modificado de L no puede incorporarse a la función principal. Por ejemplo: en la siguiente función print (), la función se ha modificado L=L->nexty el valor modificado no se recupera.

    #include <iostream>
    using namespace std;
    typedef struct LNode{
        int data;
        struct LNode* next;
    }LNode;
    void insertElem(LNode *L,int x){
        while(L->next!=NULL){
            L=L->next;
        }
        //此时L的下一个为NULL
        L->next = (LNode*)malloc(sizeof(sizeof(LNode)));
        L->next->data = x;
        L->next->next = NULL;
    }
    void print(LNode *L){
        while (L->next!=NULL){
            L = L->next;
            cout<<L->data<<" ";
        }
        cout<<endl;
    }
    int  main() {
        LNode *L;
        L->data = -1;//头结点
        L->next = NULL;
        for(int i=0;i<10;i++){
            insertElem(L,i);
        }
       print(L);
        return 0;
    }
    

    Problema de inversión (408 sitios de prueba importantes)

    void reverse(int a[],int left,int right,int k){
    	int temp;
        for(int i=left,j=right;i<left+k && i<j;i++,j--){
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
    }
    
  1. Los elementos k (k <n) del extremo frontal de la matriz de longitud n se invierten en el extremo posterior de la matriz, los datos no se pierden y la posición de los elementos restantes no importa.

    reverse(a,0,n - 1,k);

  2. Los elementos k (k <n) en el frente de la matriz de longitud n se mueven hacia la parte posterior de la matriz en el orden original, los datos no se pierden y la posición de los elementos restantes es irrelevante.

    El proceso de k primero y luego 1 en orden inverso

    reverse(a,0,k-1,k);

    reverse(a,0,n-1,k);

  3. Los elementos (X 0 , X 1 , ..., X n-1 ) en la matriz se convierten (X p , X p + 1 , ..., X n-1 , X 0 , X 1 , ..., X p-1 ), es decir Ciclo dejado por p posiciones.

    "Antes de tirar"

    Requisitos:

    123456789 -> 456789123

    O trata 123 en su conjunto

    => 321 456789

    => 321 987654

    => 456789123

    reverse(a,0,p-1,p);
    reverse(a,p,n-1,n-p);
    reverse(a,0,n-1,n);
    

    "Más tarde de antemano"

    Requisitos:

    123456789 -> 789123456

    Tratar 123456 como un todo

    => 654321 789

    => 654321 987

    => 789123456

    reverse(a,0,n-p-1,n-p);
    reverse(a,n-p,n-1,p);
    reverse(a,0,n-1,n);
    
Publicado 22 artículos originales · elogiado 0 · visitas 781

Supongo que te gusta

Origin blog.csdn.net/sjxgghg/article/details/105594813
Recomendado
Clasificación