Registro de aprendizaje de estructura de datos 3-lista enlazada individualmente
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
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 *next
inicializa 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
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 malloc
generar un nodo y *next
apuntarlo NULL
.
1.3.4 Recorrido de la tabla
Recorrido de tabla que podemos utilizar while
para realizar hasta *next == NULL
.
1.3.5 Destrucción de la mesa
Para la destrucción de la mesa, podemos atravesar, free
y hasta el final.
1.3.6 Inserción de nodo
Podemos encontrar la posición anterior del nodo a insertar atravesando + contando , registrarlo como LastNode
y realizar las siguientes operaciones:
- La creación de una buena información de nodo a insertar, denota
ThisNode
, yThisNode
la*next
asignación aLastNode
la*next
. De esta forma, el nodo que insertamos apuntará a nuestro próximo nodo. - Será
LastNode
la dirección*next
asignadaThisNode
. 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
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:
- Leer y guardar
LastNode
la*next
dirección, esto es lo que queremos eliminarThisNode
. - Ponemos
LastNode
el*next
puntoThisNode
de*next
. En este punto, si volvemos a recorrer la lista, ya no se puede recorrerThisNode
, se omite free
ApagadoThisNode
porque 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;
}