<Estructura de datos> Lista enlazada simple

contenido

1. Tabla de orden de comparación

2. Concepto

3. Trabajo necesario

       3.1 Crear una lista enlazada individualmente

       3.2 Nodo de aplicación dinámica

       3.3, impresión de lista de enlaces individuales

       3.4 Destruir la lista de enlaces simples

Cuarto, adiciones, supresiones y revisiones.

       4.1 Insertar datos

                enchufe de cabeza

                tapón de cola

                inserte x antes de la posición pos

                insertar x después de la posición pos

        4.2 Eliminar datos

                eliminación de encabezado

                eliminación de la cola

                Eliminar los datos después de pos

                eliminar datos en pos

        4.3, búsqueda de lista enlazada simple

        4.4, modificar la lista de enlaces individuales

Cinco, el código total

       Archivo SList.h

       Archivo SList.c

       Archivo de prueba.c


1. Tabla de orden de comparación

En la sección anterior, aprendimos sobre la tabla de secuencia, y ya conocemos sus ventajas y desventajas, de la siguiente manera:

ventaja:

  • Espacio físico continuo, conveniente para el acceso aleatorio de subíndice

defecto:

  1. Insertar datos, ampliar la capacidad cuando no hay suficiente espacio y ampliar la capacidad tiene consumo de rendimiento
  2. Insertar y eliminar datos en la cabecera o en la posición intermedia requiere mover los datos, lo cual es ineficiente
  3. La expansión de la capacidad es generalmente un aumento de 2 veces, lo que seguramente tendrá una cierta cantidad de desperdicio de espacio. Por ejemplo, la capacidad actual es 100 y la capacidad aumenta a 200 cuando está llena. Continuamos insertando 5 datos y no se insertan datos más tarde, por lo que se desperdician 95 espacios de datos. Si cada expansión es un poco menor, dará lugar a una expansión frecuente, y la expansión frecuente también tendrá un consumo de rendimiento.

Combinando las deficiencias de la tabla de secuencias, podemos concluir las siguientes conclusiones: la tabla de secuencias no puede solicitar y liberar espacio a pedido , es imposible almacenar una pieza de datos para solicitar una pieza de espacio y eliminar una pieza de datos para liberar un trozo de espacio.

Sobre la base de las deficiencias de la lista secuencial, se diseñó una estructura de lista enlazada. El texto comienza:

2. Concepto

Concepto : la lista enlazada es una estructura de almacenamiento no consecutiva y no secuencial en la estructura de almacenamiento físico. El orden lógico de los elementos de datos se realiza a través del orden de enlace de los punteros en la lista enlazada.
La estructura de la lista enlazada es algo similar a la de un tren.Cada vagón del tren está unido por un pestillo y un gancho .

Ahora que la lista enlazada quiere lograr una solicitud bajo demanda, ¿cómo administrarla? La tabla de secuencia anterior tiene un puntero para señalar la ubicación de los primeros datos, eso está bien, porque la tabla de secuencia se almacena continuamente, y si conoce la primera, conocerá la i-ésima, y ​​ahora la lista enlazada necesita un dato, solo malloc uno, no el físico.El espacio de arriba es continuo.

De hecho, la gestión de la lista enlazada es muy simple. Se necesita un puntero para apuntar al nodo de los primeros datos. Para encontrar los siguientes datos, se necesita almacenar otro puntero en este nodo, apuntando a la dirección de el nodo de los datos siguientes. Si no hay ningún nodo de datos siguiente, o NULL

  • Explicación del dibujo:

  •  demostración de código:
int main()
{
	SListNode* slist = NULL;
	SListNode* n1 = malloc(sizeof(SListNode));
	SListNode* n2 = malloc(sizeof(SListNode));
	SListNode* n3 = malloc(sizeof(SListNode));
	n1->data = 1;
	n2->data = 2;
	n3->data = 3;
	n1->next = n2;
	n2->next = n3;
	n3->next = NULL;
	slist = n1;
	return 0;
}

Realizamos la depuración F10 de acuerdo con el código anterior para observar el proceso de formación de la lista enlazada individualmente:

 El diagrama anterior es una estructura lógica, que es una estructura idealizada. De hecho, no hay ninguna flecha que apunte hacia ella. La estructura lógica se dibuja para facilitar la comprensión, pero la operación real se basa en la estructura física.

 Aviso:

  1. Como se puede ver en la figura anterior, la estructura de la cadena es lógicamente continua, pero no necesariamente físicamente continua.
  2. En realidad, los nodos generalmente se aplican desde el montón.
  3. El espacio solicitado del montón se asigna de acuerdo con una determinada estrategia, y el espacio solicitado dos veces puede ser continuo o no.

No es necesario inicializar la lista vinculada, porque la lista vinculada no tiene nodos cuando inicialmente está vacía

3. Trabajo necesario

3.1 Crear una estructura de lista de enlace simple

  • Archivo SList.h:
typedef int SLTDataType; //方便以后存储其它类型数据,本文以int为例
//创建单链表结构
typedef struct SListNode
{
	SLTDataType data; //值
	struct SListNode* next; //存储下一个节点的地址
}SListNode, SLN;

3.2 Nodo de aplicación dinámica

Debido a que los datos recién agregados deben vincularse en las operaciones posteriores, como la conexión de la cola y la conexión de la cabeza, es necesario solicitar un nodo para vincular los datos recién agregados.

  • Archivo SList.c:
SListNode* BuySListNode(SLTDataType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	else
	{
		newnode->data = x;
		newnode->next = NULL;
	}
	return newnode;
}

3.3, impresión de lista de enlaces individuales

  • Pensamiento:

La lista vinculada puede estar vacía y no hay datos en absoluto, por lo que no es necesario afirmar la afirmación. Para imprimir una lista enlazada, primero obtenga la dirección del primer nodo, defina un puntero cur para apuntar a phead, cuando cur no sea NULL, imprima los datos de la lista enlazada a su vez y asigne cur como la dirección del siguiente nodo

  • Archivo SList.h:
//打印单链表
void SListPrint(SListNode* phead);
  • Archivo SList.c:
//打印单链表
void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}
  • Archivo de prueba.c:
int main()
{
	SListNode* slist = NULL;
	SListNode* n1 = malloc(sizeof(SListNode));
	SListNode* n2 = malloc(sizeof(SListNode));
	SListNode* n3 = malloc(sizeof(SListNode));
	n1->data = 1;
	n2->data = 2;
	n3->data = 3;
	n1->next = n2;
	n2->next = n3;
	n3->next = NULL;
	slist = n1;
	SListPrint(slist);
	return 0;
}
  • El efecto es el siguiente:

  •  Explicación del dibujo:

3.4 Destruir la lista de enlaces simples

  • Pensamiento:

Los datos se liberan uno por uno, a diferencia de las tablas secuenciales. No olvide configurar la lista para que se vacíe después del lanzamiento

  • Archivo SList.h:
//销毁单链表
void SListDestroy(SListNode** pphead);
  • Archivo SList.c:
//销毁单链表
void SListDestroy(SListNode** pphead)
{
	assert(pphead);
	SListNode* cur = *pphead;
	while (cur)
	{
		SListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

Cuarto, adiciones, supresiones y revisiones.

4.1 Insertar datos

enchufe de cabeza

  • Pensamiento:

El proceso de inserción de la cabeza es relativamente simple que la inserción de la cola a continuación. No necesita encontrar la cola como la inserción de la cola para realizar el enlace de los nodos. La inserción de la cabeza solo necesita apuntar la lista a la dirección del nodo de la nueva cabeza. inserción, y luego apunte el nodo a Los primeros datos originales pueden ser. Sin embargo, debe tenerse en cuenta que el complemento de encabezado también debe pasar la dirección como el complemento de cola, porque el cambio del parámetro formal no afectará el parámetro real.

Y aquí se requiere la afirmación de aserción pphead, porque la dirección pphead de la lista no puede estar vacía

  • Dibujo de demostración (estructura lógica):

  •  Archivo SList.h:
//头插
void SListPushFront(SListNode** pphead, SLTDataType x);
  • Archivo SList.c:
//头插
void SListPushFront(SListNode** pphead, SLTDataType x)
{
	assert(pphead);
	SListNode* newnode = BuySListNode(x); //创建一个新的节点
	newnode->next = *pphead;
	*pphead = newnode;
}
  • Dibujo de demostración (estructura física):

  •  Archivo de prueba.c:
int main()
{
	SListNode* slist = NULL;
	for (int i = 0; i < 10; i++)
	{
		SListPushBack(&slist, i); //尾插10个数据
	}
	for (int i = -5; i < 0; i++)
	{
		SListPushFront(&slist, i); //头插5个数据
	}
	SListPrint(slist); //打印
	return 0;
}
  • El efecto es el siguiente:

tapón de cola

  • Pensamiento:

Hay dos casos para la inserción de la cola, que están vacíos y no vacíos.

  1. Si está vacío, dale el nodo recién abierto a phead
  2. Si no está vacío, debe vincular los datos recién agregados al último nodo de los datos originales. En este momento, debe usar el recorrido para encontrar el último nodo en la lista vinculada original. Simplemente cree una variable de puntero que apunte a la cola to phead, loop Determina si tail->next está vacío. Cuando está vacío, el bucle se detiene automáticamente. En este momento, tail apunta al último nodo de la lista enlazada original.
  •  Demostración de dibujo:

  • Aviso:
  1. El parámetro formal es una copia temporal del parámetro real. El cambio del parámetro formal no afecta el parámetro real. Aquí, la lista debe cambiarse. El phead es una copia temporal de la lista. Puntero, así que si lo desea para pasar la dirección del puntero, debe usar el puntero secundario para recibirlo.
  2. Aquí debemos afirmar pphead, pphead no debe estar vacío, incluso si la lista enlazada está vacía, slist es la dirección y la dirección de slist pphead no puede estar vacía
  • Archivo SList.h:
//尾插
void SListPushBack(SListNode** pphead, SLTDataType x);
  • Archivo SList.c:
//尾插
void SListPushBack(SListNode** pphead, SLTDataType x) 
{
	assert(pphead);// pphead是一定不能为空的,哪怕链表是空,slist是地址,slist的地址不能为空
	SListNode* newnode = BuySListNode(x);
	if (*pphead == NULL) //pphead就是slist的地址,*pphead就是slist本身
	{
		*pphead = newnode;
	}
	else
	{
		//找尾
		SListNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}
  • Archivo de prueba.c:
int main()
{
	SListNode* slist = NULL;
	for (int i = 0; i < 10; i++)
	{
		SListPushBack(&slist, i);
	}
	SListPrint(slist);
	return 0;
}
  • El efecto es el siguiente:

 

inserte x antes de la posición pos

  • Pensamiento:

Aquí pos es el puntero del nodo, y pos se encuentra a través de la función SListFind Por ejemplo, si desea insertar 30 antes del nodo de 3, debe encontrar el nodo anterior de pos, para que los nodos de la lista enlazada se pueden vincular en secuencia, y la última inserción del texto anterior También es necesario encontrar el final. Podemos agregar una variable de puntero prev y atravesar prev a su vez. Si es next = pos, stop, si no es igual, continuar Después de encontrar, cree un nuevo nodo para realizar la vinculación secuencial de los nodos. Por supuesto, la situación anterior se limita al hecho de que pos no está en el nodo principal. Si está en el nodo principal, debe discutirse por separado, porque prev es NULL en este momento, pero en este momento es equivalente al enchufe de la cabeza, simplemente llame a la función del enchufe de la cabeza.

  • Demostración de dibujo:

  •  Archivo SList.h:
//在pos位置之前插入
void SListInsert(SListNode** pphead, SListNode* pos, SLTDataType x);
  • Archivo SList.c:
//在pos位置之前插入
void SListInsert(SListNode** pphead, SListNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	//1、pos是第一个节点
	//2、pos不是第一个节点
	if (pos == *pphead)
	{
		SListPushFront(pphead, x);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SListNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}
  • Archivo de prueba.c:
int main()
{
	SListNode* slist = NULL;
	for (int i = 1; i < 4; i++)
	{
		SListPushBack(&slist, i); //尾插3个数据
	}
	SListPrint(slist); //打印
	SListNode* pos = SListFind(slist, 3); 
	if (pos != NULL)
	{
		SListInsert(&slist, pos, 300);
	}
	SListPrint(slist); //打印

	pos = SListFind(slist, 1);
	if (pos != NULL)
	{
		SListInsert(&slist, pos, 100);
	}
	SListPrint(slist); //打印
	return 0;
}
  • El efecto es el siguiente:

 

insertar x después de la posición pos

  • Pensamiento:

De hecho, la lista enlazada individualmente debe insertarse después de la posición pos, porque entonces no hay necesidad de pasar el pphead. Hay dos esquemas, primero use next para registrar el siguiente nodo de pos, luego cree un nuevo nodo, deje que el siguiente nodo de pos apunte a newnode, y luego deje que el siguiente nodo de newnode apunte al siguiente. La segunda es no definir next, apuntar el siguiente nodo de newnode al siguiente nodo de pos, y luego apuntar el siguiente nodo de pos a newnode El orden de los dos no se puede invertir.

  •  Archivo SList.h:
//在pos位置之后插入
void SListInsertAfter(SListNode* pos, SLTDataType x);
  • Archivo SList.c:
//在pos位置之后插入
void SListInsertAfter(SListNode* pos, SLTDataType x)
{
	assert(pos);
	//法一:
	SListNode* next = pos->next;
	SListNode* newnode = BuySListNode(x);
	pos->next = newnode;
	newnode->next = next;
	/*
	法二:
	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
	*/
}

La estructura y el proceso de prueba son los mismos que insertar x antes de pos arriba, por lo que no entraré en detalles aquí.

4.2 Eliminar datos

eliminación de encabezado

  • Pensamiento:

La eliminación del encabezado debe clasificarse. El primer tipo es que no hay ningún nodo, que está vacío por sí mismo y se puede devolver directamente. La segunda es que hay un nodo, puede crear una variable de puntero al lado para guardar el siguiente nodo del primer nodo y luego asignar al lado de *pphead, pero preste atención para liberar el primer nodo.

  • Demostración de dibujo:

  •  Archivo SList.h:
//头删
void SListPopFront(SListNode** pphead);
  • Archivo SList.c:
//头删
void SListPopFront(SListNode** pphead)
{
	assert(pphead);
	//1、空
	//2、非空
	if (*pphead == NULL)
	{
		return;
	}
	else
	{
		SListNode* next = (*pphead)->next;
		free(*pphead);
		*pphead = next;
	}
}
  • Archivo de prueba.c:
int main()
{
	SListNode* slist = NULL;
	for (int i = 1; i < 10; i++)
	{
		SListPushBack(&slist, i); //尾插10个数据
	}
	SListPrint(slist); //打印
	for (int i = 0; i < 4; i++)
	{
		SListPopFront(&slist); //头删4次
	}
	SListPrint(slist); //打印
	return 0;
}
  • El efecto es el siguiente:

eliminación de la cola

  • Pensamiento:

ley uno:

En circunstancias normales, la eliminación de la cola primero debe encontrar la cola y definir una cola variable de puntero como la inserción de la cola. Cuando la siguiente cola apunta a NULL, se encuentra la cola. Cuando se liberan los últimos datos, recuerde que el principio de enlace simple list es el último. El nodo apunta a un NULL vacío, por lo que es necesario definir una variable de puntero anterior. Cuando el recorrido de la cola no está vacío, asígnelo a anterior. Cuando la cola llega al final, anterior es el anterior. En este momento, configure prev->next a NULL Eso es todo. Esta situación se limita a múltiples nodos y es difícil garantizar casos extremos, como solo un nodo o ningún nodo, por lo que debe manejarse en múltiples casos.

  • Demostración de dibujo:

Sin nodos:

un nodo:

 Múltiples nodos:

  •  El código es el siguiente: (archivo SList.c)
//尾删 -- 法一
void SListPopBack(SListNode** pphead)
{
	assert(pphead);
	//1、空
	//2、一个节点
	//3、多个节点

	/*暴力检查为空:assert(*pphead != NULL);*/
	//温柔检查为空:
	if (*pphead == NULL)
	{
		return;
	}
	else if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SListNode* prev = NULL;
		SListNode* tail = *pphead;
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		prev->next = NULL;
	}
}

 Ley dos:

También puede simplemente definir una variable de puntero tail y averiguar si tail->next->next es NULL. Si es así, suelte el siguiente apuntado por tail y configúrelo en vacío. Este método parece más conciso en el código, pero es fácil escribir errores. , Método de recomendación personal 1, las desventajas de este método son las mismas que las del método solo aplicable a múltiples nodos, y también se debe considerar el caso de vacío y un nodo.

  •  El código es el siguiente: (archivo SList.c)
//尾删
void SListPopBack(SListNode** pphead)
{
	assert(pphead);
//空…… 同上
//一个节点…… 同上
//多个节点:如下
	SListNode* tail = *pphead;
	while (tail->next->next != NULL)
	{
		tail = tail->next;
	}
	free(tail->next);
	tail->next = NULL;
}
  • Archivo de prueba.c:
int main()
{
	SListNode* slist = NULL;
	for (int i = 1; i < 5; i++)
	{
		SListPushBack(&slist, i); //尾插4个数据
	}
	SListPrint(slist); //打印
	for (int i = 0; i < 5; i++)
	{
		SListPopBack(&slist); //尾删5次
	}
	SListPrint(slist); //打印
	return 0;
}
  • El efecto es el siguiente:

Eliminar los datos después de pos

  • Pensamiento:

Al igual que los datos insertados en pos, debe usar la función SListFind para encontrarlo y luego eliminarlo. Por ejemplo, quiero eliminar 3, pero tiene que tener qué nodo, así que cree anterior para apuntar al nodo anterior de pos, y luego libérese. , y luego apunte el siguiente nodo de prev al siguiente nodo de pos, y luego suelte pos free. Por supuesto, la situación anterior se limita a que pos no es la cabeza. Si pos es la cabeza, entonces prev está vacío, por lo que debe discutirse por separado, simplemente llame a la eliminación de la cabeza.

  • Demostración de dibujo:

  •   Archivo SList.h:
//删除pos位置
void SListErase(SListNode** pphead, SListNode* pos);
  • Archivo SList.c:
//删除pos位置
void SListErase(SListNode** pphead, SListNode* pos)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SListPopFront(pphead);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
  • Archivo de prueba.c:
int main()
{
	SListNode* slist = NULL;
	for (int i = 1; i <= 5; i++)
	{
		SListPushBack(&slist, i); //尾插5个数据
	}
	SListPrint(slist); //打印
	SListNode* pos = SListFind(slist, 3); 
	if (pos != NULL)
	{
		SListErase(&slist, pos); //删3
	}
	SListPrint(slist); //打印
	pos = SListFind(slist, 1);
	if (pos != NULL)
	{
		SListErase(&slist, pos); //删1
	}
	SListPrint(slist); //打印
	return 0;
}
  • El efecto es el siguiente:

eliminar datos en pos

  • Pensamiento:

En comparación con la eliminación de pos, es más conveniente eliminar pos, porque no es necesario pasar la dirección de phead. Simplemente use next para guardar el siguiente nodo de pos, deje que el siguiente nodo de pos apunte al siguiente nodo de next, realice el enlace de la lista enlazada y luego libere pos gratis. Pero debe tenerse en cuenta que cuando pos es cola, el siguiente nodo después de pos está vacío, por lo que debe discutirse por separado, simplemente llame a la eliminación de cola.

  •   Archivo SList.h:
//删除pos后位置
void SListEraseAfter(SListNode* pos);
  • Archivo SList.c:
//删除pos后位置
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	SListNode* next = pos->next;
	if (next)
	{
		pos->next = next->next;
		free(next);
		next = NULL;
	}
}

4.3, búsqueda de lista enlazada simple

  • Pensamiento:

La búsqueda de lista enlazada individualmente es realmente muy simple. Solo necesita definir un puntero cur para apuntar a la cabeza phead y atravesar cur (cur = cur -> siguiente) a su vez para ver si los datos señalados por él son iguales a X. Si es igual, devuelve cur, de lo contrario, devuelve NULL.

  • Archivo SList.h:
//查找
SListNode* SListFind(SListNode* phead, SLTDataType x);
  • Archivo SList.c:
//查找
SListNode* SListFind(SListNode* phead, SLTDataType x)
{
	SListNode* cur = phead;
	while (cur != NULL)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}
  • Archivo de prueba.c:
int main()
{
	SListNode* slist = NULL;
	for (int i = 1; i < 10; i++)
	{
		SListPushBack(&slist, i); //尾插10个数据
	}
	SListPrint(slist); //打印
	SListNode* pos = SListFind(slist, 3);
	if (pos != NULL)
	{
		printf("找到了,地址为%p\n", pos);
	}
	return 0;
}
  • El efecto es el siguiente:

4.4, modificar la lista de enlaces individuales

La modificación es relativamente sencilla, solo necesitamos hacer ajustes en base a la búsqueda, cuando encontramos un dato a modificar, lo modificamos a través de la dirección devuelta.

  • Archivo de prueba.c:
int main()
{
	SListNode* slist = NULL;
	for (int i = 1; i < 4; i++)
	{
		SListPushBack(&slist, i); //尾插10个数据
	}
	SListPrint(slist); //打印
	SListNode* pos = SListFind(slist, 3);
	if (pos != NULL)
	{
		printf("找到了,地址为%p\n", pos);
		pos->data *= 10;
	}
	SListPrint(slist); //打印
	return 0;
}
  • El efecto es el siguiente:

Cinco, el código total

Archivo SList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType; //方便以后存储其它类型数据,本文以int为例
//创建单链表结构
typedef struct SListNode
{
	SLTDataType data; //值
	struct SListNode* next; //存储下一个节点的地址
}SListNode, SLN;
//打印单链表
void SListPrint(SListNode* phead);
//销毁单链表
void SListDestroy(SListNode** pphead);

//尾插
void SListPushBack(SListNode** pphead, SLTDataType x);
//头插
void SListPushFront(SListNode** pphead, SLTDataType x);
//尾删
void SListPopBack(SListNode** pphead);
//头删
void SListPopFront(SListNode** pphead);
//查找
SListNode* SListFind(SListNode* phead, SLTDataType x);

//在pos位置之前插入
void SListInsert(SListNode** pphead, SListNode* pos, SLTDataType x);
//在pos位置之后插入
void SListInsertAfter(SListNode* pos, SLTDataType x);

//删除pos位置
void SListErase(SListNode** pphead, SListNode* pos);
//删除pos后位置
void SListEraseAfter(SListNode* pos);

Archivo SList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
//打印单链表
void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}
//创建新节点
SListNode* BuySListNode(SLTDataType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	else
	{
		newnode->data = x;
		newnode->next = NULL;
	}
	return newnode;
}
//销毁单链表
void SListDestroy(SListNode** pphead)
{
	assert(pphead);
	SListNode* cur = *pphead;
	while (cur)
	{
		SListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}
//查找
SListNode* SListFind(SListNode* phead, SLTDataType x)
{
	SListNode* cur = phead;
	while (cur != NULL)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//尾插
void SListPushBack(SListNode** pphead, SLTDataType x)
{
	assert(pphead);// pphead是一定不能为空的,哪怕链表是空,slist是地址,slist的地址不能为空
	SListNode* newnode = BuySListNode(x);
	if (*pphead == NULL) //pphead就是slist的地址,*pphead就是slist本身
	{
		*pphead = newnode;
	}
	else
	{
		//找尾
		SListNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}
//头插
void SListPushFront(SListNode** pphead, SLTDataType x)
{
	assert(pphead);
	SListNode* newnode = BuySListNode(x); //创建一个新的节点
	newnode->next = *pphead;
	*pphead = newnode;
}
//尾删 
void SListPopBack(SListNode** pphead)
{
	assert(pphead);
	//1、空
	//2、一个节点
	//3、多个节点

	/*暴力检查为空:assert(*pphead != NULL);*/
	//温柔检查为空:
	if (*pphead == NULL)
	{
		return;
	}
	else if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		//法一:
		SListNode* prev = NULL;
		SListNode* tail = *pphead;
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		prev->next = NULL;

		//法二:
		/*SListNode* tail = *pphead;
		while (tail->next->next != NULL)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;*/
	}
}
//头删
void SListPopFront(SListNode** pphead)
{
	assert(pphead);
	//1、空
	//2、非空
	if (*pphead == NULL)
	{
		return;
	}
	else
	{
		SListNode* next = (*pphead)->next;
		free(*pphead);
		*pphead = next;
	}
}

//在pos位置之前插入
void SListInsert(SListNode** pphead, SListNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	//1、pos是第一个节点
	//2、pos不是第一个节点
	if (pos == *pphead)
	{
		SListPushFront(pphead, x);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SListNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}
//在pos位置之后插入
void SListInsertAfter(SListNode* pos, SLTDataType x)
{
	assert(pos);
	//法一:
	SListNode* next = pos->next;
	SListNode* newnode = BuySListNode(x);
	pos->next = newnode;
	newnode->next = next;
	/*
	法二:
	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
	*/
}


//删除pos位置
void SListErase(SListNode** pphead, SListNode* pos)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SListPopFront(pphead);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}
//删除pos后位置
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	SListNode* next = pos->next;
	if (next)
	{
		pos->next = next->next;
		free(next);
		next = NULL;
	}
}

Archivo de prueba.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"
//void test1()
//{
//	SListNode* slist = NULL;
//	SListNode* n1 = malloc(sizeof(SListNode));
//	SListNode* n2 = malloc(sizeof(SListNode));
//	SListNode* n3 = malloc(sizeof(SListNode));
//	n1->data = 1;
//	n2->data = 2;
//	n3->data = 3;
//	n1->next = n2;
//	n2->next = n3;
//	n3->next = NULL;
//	slist = n1;
//	SListPrint(slist);
//}

void test2()
{
	SListNode* slist = NULL;
	for (int i = 0; i < 10; i++)
	{
		SListPushBack(&slist, i); //尾插10个数据
	}
	for (int i = -5; i < 0; i++)
	{
		SListPushFront(&slist, i); //头插5个数据
	}
	SListPrint(slist); //打印
}

void test3()
{
	SListNode* slist = NULL;
	for (int i = 1; i < 5; i++)
	{
		SListPushBack(&slist, i); //尾插4个数据
	}
	SListPrint(slist); //打印
	for (int i = 0; i < 5; i++)
	{
		SListPopBack(&slist); //尾删5次
	}
	SListPrint(slist); //打印
}

void test4()
{
	SListNode* slist = NULL;
	for (int i = 1; i < 10; i++)
	{
		SListPushBack(&slist, i); //尾插10个数据
	}
	SListPrint(slist); //打印
	for (int i = 0; i < 4; i++)
	{
		SListPopFront(&slist); //头删4次
	}
	SListPrint(slist); //打印
}

void test5()
{
	SListNode* slist = NULL;
	for (int i = 1; i < 4; i++)
	{
		SListPushBack(&slist, i); //尾插10个数据
	}
	SListPrint(slist); //打印
	SListNode* pos = SListFind(slist, 3);
	if (pos != NULL)
	{
		printf("找到了,地址为%p\n", pos);
		pos->data *= 10;
	}
	SListPrint(slist); //打印
}

void test6()
{
	SListNode* slist = NULL;
	for (int i = 1; i < 4; i++)
	{
		SListPushBack(&slist, i); //尾插10个数据
	}
	SListPrint(slist); //打印
	SListNode* pos = SListFind(slist, 3);
	if (pos != NULL)
	{
		SListInsert(&slist, pos, 300);
	}
	SListPrint(slist); //打印

	pos = SListFind(slist, 1);
	if (pos != NULL)
	{
		SListInsert(&slist, pos, 100);
	}
	SListPrint(slist); //打印
}
int main()
{
	SListNode* slist = NULL;
	for (int i = 1; i <= 5; i++)
	{
		SListPushBack(&slist, i); //尾插5个数据
	}
	SListPrint(slist); //打印
	SListNode* pos = SListFind(slist, 3); 
	if (pos != NULL)
	{
		SListErase(&slist, pos); //删3
	}
	SListPrint(slist); //打印
	pos = SListFind(slist, 1);
	if (pos != NULL)
	{
		SListErase(&slist, pos); //删1
	}
	SListPrint(slist); //打印
	return 0;
}

Supongo que te gusta

Origin blog.csdn.net/bit_zyx/article/details/123493724
Recomendado
Clasificación