Plant Wars lidera la lista enlazada doblemente circular - Pure C

"Las flores flotan y el agua fluye, una especie de mal de amores y dos preocupaciones"
"No hay forma de eliminar este sentimiento, así que levanté las cejas, pero llegó a mi corazón".

prefacio

inserte la descripción de la imagen aquí
Estas dos listas enlazadas son las más utilizadas en la vida real. Una lista enlazada acíclica unidireccional sin cabecera. y una lista doblemente enlazada con encabezado.
Lista enlazada acíclica unidireccional sin cabeza : la estructura es simple y, por lo general, no se usa para almacenar datos solos. En la práctica, es más una subestructura de otras estructuras de datos , como cubos hash, listas de adyacencia de gráficos, etc. Además, esta estructura aparece mucho en la entrevista de prueba escrita . Lista enlazada doblemente circular con encabezado : La estructura es la más compleja y generalmente se usa para almacenar datos por separado. Las estructuras de datos de listas enlazadas utilizadas en la práctica son todas listas enlazadas doblemente circulares principales. Además, aunque la estructura de esta estructura es compleja, se encontrará que la estructura traerá muchas ventajas después de usar el código para implementarla, pero la implementación es simple y lo sabremos después de implementar el código.

1. Crea la estructura

Nota: el typedef funciona en la línea 7. Entonces, 5 y 6 también necesitan escribir el tipo struct ListNode.

typedef int LNDataType;

typedef struct ListNode
{
    
    
	  struct ListNode* prev;
 	  struct ListNode* next;
      LNDataType val;
}LN;

2. malloc nuevo nodo

Nota: Es necesario juzgar si el nodo recién abierto está vacío.

//申请一个新节点
LN* BuynewNode(LNDataType x)
{
    
    
	LN* newNode = (LN*)malloc(sizeof(LN));
	if (newNode == NULL)
	{
    
    
		printf("malloc fail");
		exit(-1);
	}
	newNode->next = NULL;
	newNode->prev = NULL;
	newNode->val = x;
	return newNode;
}

3. Crea un ganglio centinela

Nota : debido a que se debe cambiar el contenido del puntero de plist, es decir, se debe cambiar el punto del puntero de plist, por lo que se debe pasar la dirección de plist.

Una oración es: cuyo contenido debe cambiarse, la dirección de quien debe cambiarse .

Aquí hay un punto muy ingenioso y muy inteligente, es decir, el sucesor y el predecesor de phead se están apuntando a sí mismos (phead), aquí está el nodo de bit centinela que imita la biblioteca STL de C++.

Solo puedo admirar al gran dios que inventó estas cosas. Si el ganglio centinela se diseña de esta manera, la posterior inserción y eliminación de la cola son particularmente ingeniosas.
inserte la descripción de la imagen aquíinserte la descripción de la imagen aquí

prueba.c

	LN* plist = NULL;
	ListNodeInit(&plist);

Lista.h

//初始化节点
void ListNodeInit(LN** pphead)
{
    
    
	LN* newNode = BuynewNode(0);
	*pphead = newNode;
	(*pphead)->next = *pphead;
	(*pphead)->prev = *pphead;
}

4. Tapón trasero

Nota: El motivo de la afirmación es que, aunque la lista enlazada no tenga un nodo, la lista enlazada tiene al menos una cabeza, por lo que la cabeza p no debe estar vacía.

La razón por la cual la dirección no se pasa aquí es porque no necesita cambiar el punto de plist, lo que cambia es el valor en la estructura a la que apunta plist.

La situación de inserción de cola de múltiples nodos se muestra en la figura.
inserte la descripción de la imagen aquí
La cola de un nodo.inserte la descripción de la imagen aquí

//尾插
void ListNodePushBack(LN* phead, LNDataType x)
{
    
    
	assert(phead);
	LN* newNode = BuynewNode(x);
	LN* tail = phead->prev;
	tail->next = newNode;
	newNode->prev = tail;
	newNode->next = phead;
	phead->prev = newNode;
}

5. Imprimir

Nota: Debido a la cabeza, cur comienza desde la segunda posición.

//打印
void ListNodePrint(LN* phead)
{
    
    
	LN* cur = phead->next;
	while (cur != phead)
	{
    
    
		printf("%d ", cur->val);
		cur = cur->next;
	}
	printf("\n");
}

6. Eliminación de cola

Tenga en cuenta que el nodo principal no se puede eliminar. Liberar el nodo principal generará un puntero salvaje y provocará un acceso ilegal cuando se vuelva a acceder.
Así que use afirmación para afirmar que no es el primer nodo.

//尾删
void ListNodePopBack(LN* phead)
{
    
    
	assert(phead);
	assert(phead->next != phead);
	LN* tail = phead->prev;
	LN* tailPrev = tail->prev;
	free(tail);
	tail = NULL;
	phead->prev = tailPrev;
	tailPrev->next = phead;
}

7. Encabezado

Es mejor usar next para registrar el siguiente nodo. Es conveniente y claro.

//头插
void ListNodePushFront(LN* phead, LNDataType x)
{
    
    
	assert(phead);
	LN* newNode = BuynewNode(x);
	LN* next = phead->next;
	phead->next = newNode;
	newNode->prev = phead;
	newNode->next = next;
	next->prev = newNode;
}

8. Insertar antes de la posición especificada pos

En general, cuando
inserte la descripción de la imagen aquísólo hay un nodo.
inserte la descripción de la imagen aquí
El siguiente código funciona en ambos casos.

//指定位置前插入,极限是头插
void ListNodeInsert(LN* pos, LNDataType x)
{
    
    
	if (pos == NULL)
	{
    
    
		printf("没有找到这个数\n");
		return;
	}
	LN* newNode = BuynewNode(x);
	LN* tailPrev = pos->prev;
	tailPrev->next = newNode;
	newNode->prev = tailPrev;
	newNode->next = pos;
	pos->prev = newNode;
}

9. Elimine el nodo pos en la ubicación especificada

Caso normal
inserte la descripción de la imagen aquí
Limitar eliminación de cola
inserte la descripción de la imagen aquí
El siguiente código se aplica a ambos casos.

//指定位置删除
void ListNodeErease(LN* phead, LN* pos)
{
    
    
	if (pos == phead || pos == NULL)
	{
    
    
		printf("pos指向头,或为空\n");
		return;
	}
	LN* posPrev = pos->prev;
	LN* posNext = pos->next;
	posPrev->next = posNext;
	posNext->prev = posPrev;
	free(pos);
	pos = NULL;
}

10. Destruye la lista enlazada

Nota: Esto es equivalente a gratis después de que se agote malloc. De lo contrario, se producirán pérdidas de memoria.
cur se puede dejar vacío, pero es de poca utilidad, porque cur es un parámetro formal, un parámetro formal es una copia temporal del parámetro real, y el parámetro real no se puede cambiar dejando el parámetro formal vacío. Los argumentos externos aún pueden acceder ilegalmente al espacio señalado por cur.

//链表销毁
void ListNodeDestroy(LN* phead)
{
    
    
	assert(phead);
	LN* cur = phead->next;
	LN* next = cur->next;
	while (cur != phead)
	{
    
    
		next = cur->next;
		free(cur);
		cur = NULL;
		cur = next;
	}
	free(phead);
	phead = NULL;
}

Supongo que te gusta

Origin blog.csdn.net/qq2466200050/article/details/123664698
Recomendado
Clasificación