【Registro de aprendizaje de estructura de datos 3】 —— Lista enlazada única

1. Principio

1. Breve descripción

Debido a que la tabla de secuencia es un espacio fijo, habrá algunos problemas con la tasa de espacio-tiempo. Si podemos conectar dinámicamente un nodo tras otro de alguna manera, podría ser mucho mejor. Por lo tanto, en este caso, se nos ocurrió la estructura de datos de una lista enlazada individualmente.

2. Análisis

Para listas enlazadas individualmente, definitivamente todavía necesitamos 增删改查estas funciones básicas. Además, además de la definición de un nodo, almacenamos además de los datos, debe ser capaz de incluir más necesidades para incluir un "sentido" de la estructura de datos del siguiente nodo, que luego podemos utilizar 指针en su lugar.

3. Ilustración de ideas

1.3.1 Definición de nodo

Inserte la descripción de la imagen aquí

Podemos crear una estructura que contenga dos partes: la primera parte son nuestros datos; la segunda parte almacena nuestro puntero al siguiente nodo y lo *nextinicializa al valor predeterminado NULL. Siempre que se detecte más tarde, no lo es NULL. Entonces muestra que hay nodos detrás de él. Una vez que se apunta un nodo NULL, significa que este nodo ha terminado.

1.3.2 Definición de lista vinculada

Inserte la descripción de la imagen aquí

Debido a que la estructura de toda nuestra lista vinculada es la misma, podemos tomar directamente un nodo fijo como tal 表头.
Luego, de acuerdo con la costumbre, especificamos el número de secuencia del primer nodo al que apunta el encabezado 0.

1.3.3 Inicialización de lista / nodo vinculado

Debido a que nuestra lista vinculada está compuesta por los mismos nodos, la inicialización de nuestra lista vinculada es igual a la inicialización de nuestros nodos. Entonces solo necesitamos usar para mallocgenerar un nodo y *nextapuntarlo NULL.

1.3.4 Recorrido de la tabla

Recorrido de tabla que podemos utilizar whilepara realizar hasta *next == NULL.

1.3.5 Destrucción de la mesa

Para la destrucción de la mesa, podemos atravesar, freey hasta el final.

1.3.6 Inserción de nodo

Inserte la descripción de la imagen aquí

Podemos encontrar la posición anterior del nodo a insertar atravesando + contando , registrarlo como LastNodey realizar las siguientes operaciones:

  1. La creación de una buena información de nodo a insertar, denota ThisNode, y ThisNodela *nextasignación a LastNodela *next. De esta forma, el nodo que insertamos apuntará a nuestro próximo nodo.
  2. Será LastNodela dirección *nextasignada ThisNode. De esta forma, la tabla vuelve a estar completa.
    Por ejemplo, en la figuraLastNode 是 0 ThisNode = index 是 1

1.3.7 Eliminación de nodos

Inserte la descripción de la imagen aquí

De manera similar a la inserción, todavía tenemos que recorrer la posición anterior del nodo que se eliminará y luego ejecutar este proceso:

  1. Leer y guardar LastNodela *nextdirección, esto es lo que queremos eliminar ThisNode.
  2. Ponemos LastNodeel *nextpunto ThisNodede *next. En este punto, si volvemos a recorrer la lista, ya no se puede recorrer ThisNode, se omite
  3. freeApagado ThisNodeporque no tiene sentido. La supresión de tal nodo.

1.3.7 Modificación de nodos

No hay nada que decir sobre la modificación, solo modificar los datos no cambiará la estructura de la lista enlazada, así que simplemente recorra la modificación directamente data.

1.3.8 Consulta de nodo

Para consulta, simplemente atraviesa.

2. Código

Modifique la función principal usted mismo para lograr el efecto.

#include <stdio.h>
#include <stdlib.h>

#define OK      1
#define ERROR   0

// 定义数据类型
typedef struct elemType {
    
    
    int data1;
    int data2;
}data;

//定义节点
typedef struct Node {
    
    
    data data;
    struct Node *next;
    //不能写成 Node *next 因为此时还没有typedef成功,只能用结构体嵌套的方式定义
}Node;

Node* ListInit(void);
void ListShow(Node *list);
int ListInsert(Node *list, data data_in, int index);
int ListDelect(Node *list, int index);
int ListModify(Node *List, data data_in, int index);
int ListQuery(Node *list, data data_in);

int main()
{
    
    
    Node* List = ListInit();
    data test;
    test.data1 = 1;
    test.data2 = 2;

    ListInsert(List, test, 0);
    test.data1 = 3;
    ListInsert(List, test, 1);
    ListShow(List);
    printf("-------\n");
    //ListDelect(List, 0);
    //ListShow(List);
    //printf("-------\n");
    test.data1 = 5;
    ListModify(List,test,1);
    ListShow(List);
    printf("query get %d\n", ListQuery(List, test));
    test.data1 = 88;
    printf("query get %d\n", ListQuery(List, test));
    return 0;
}

Node* ListInit(void)
{
    
    
    Node* list = (Node *)malloc(sizeof(Node));  // 创建节点

    if (list == NULL)
    {
    
    
        exit(0);    // 节点创建失败,退出
    }
    else
    {
    
    
        list->next = NULL;  // 节点初始化成功,返回节点作为表头
        return list;    
    }
}

void ListShow(Node* list)
{
    
    
    int cont = 0;

    while(list->next != NULL)   // 遍历到表末尾
    {
    
    
        list = list->next;  // 跳过表头,list变成真第一个节点
        printf("No.%d data is %d %d\n", cont, list->data.data1, list->data.data2);
        ++cont; // 这个节点已输出,cont变成下一个节点的序号
    }

}

int ListInsert(Node *list, data data_in, int index)
{
    
    
    int cont = -1;  // 初始化为 -1,简化后面操作
    Node *ThisNode = (Node *)malloc(sizeof(Node));
    
    ThisNode->data = data_in;   // 初始化创建好的节点
    ThisNode->next = NULL;  

    if (list->next == NULL) //  判断这个表是不是空表,空表就特殊处理了
    {
    
    
        list->next = ThisNode;
        return OK;
    }

    while(list->next != NULL && cont < index - 1)   //遍历 到插入的前一个节点
    {
    
    
        list = list->next; //移动到下一个节点
        ++cont; // 因为list初值是表头,cont初值-1,所以这样操作后,这句话后的list的节点序号和cont对应
    }

    ThisNode->next = list->next;    //更新操作
    list->next = ThisNode;

    return OK;
}

int ListDelect(Node *list, int index)
{
    
    
    Node *dNode = NULL;     //声明一下要删除的节点变量
    int cont = -1;  //  同理

    if (list->next == NULL)
    {
    
    
        return ERROR;   //空链表,没意义,返回错误
    }
    else
    {
    
    
        while(list->next != NULL && cont < index - 1)
        {
    
    
            list = list->next;
            ++cont;
            // 和插入一样的解释,遍历。
        }

        dNode = list->next;
        list->next = dNode->next; //    这样就跳过了dNode
        free(dNode);    //释放掉删除的Node

        return OK;
    }
}

int ListModify(Node *list, data data_in, int index)
{
    
    
    int cont = -1;

    while(list->next != NULL && cont < index) // 因为要删除,所以要遍历到它本身
    {
    
    
        list = list->next;
        ++cont;
    }
    if (cont == index)  // 确定遍历到了它
    {
    
    
        list->data = data_in;
        return OK;
    }
    else    // 理论上来说是长度不够 index比表长更长
    {
    
    
        return ERROR;
    }
}

int ListQuery(Node *list, data data_ck)
{
    
    
    int cont = 0;
    
    while(list->next != NULL)   // 查询同修改
    {
    
    
        list = list->next;
        if (list->data.data1 == data_ck.data1 && list->data.data2 == data_ck.data2)
        {
    
    
            return cont;
        }
        ++cont;
    }
    return -1;
} 

Supongo que te gusta

Origin blog.csdn.net/u011017694/article/details/109287688
Recomendado
Clasificación