<Estructura de datos> Lista enlazada circular bidireccional con encabezado

contenido

1. Concepto

2. Trabajo necesario

       2.1 Crear una estructura de lista doblemente enlazada

       2.2, inicializar la lista enlazada

       2.3 Nodo de aplicación dinámica

       2.4, imprimir lista enlazada

       2.5 Destruir la lista enlazada

3. Funciones principales

       3.1 Insertar datos antes del nodo pos

                tapón de cola

                enchufe de cabeza

        3.2 Eliminar datos de nodo en pos

                eliminación de la cola

                eliminación de encabezado

        3.3 Buscar datos

Cuarto, el código total

        Archivo lista.h

        Archivo lista.c

        Archivo de prueba.c

5. Expansión: Lista de secuencias de contraste y Lista enlazada


1. Concepto

En el artículo anterior, aprendimos sobre la lista enlazada simple y, a través del tema oj, tenemos una comprensión profunda de la lista enlazada con el nodo principal y la lista enlazada con un anillo, para hacer una revisión general. de la imagen:

En la lista vinculada que aprendimos, en realidad hay 8 tipos en total, todos los cuales son cualquier combinación de unidireccional y bidireccional, con o sin líder, y con o sin anillo.

Lo que vamos a aprender hoy es una lista enlazada circular líder de dos vías. Cuando escuchas el nombre, sientes que la estructura es muy complicada. Es mucho más complicada que la lista unidireccional sin líder. -Lista circular enlazada que has aprendido antes, y de hecho lo es. Primero, hagamos un dibujo para sentir el todo:

  • explique:
  1. Bidireccional: Es necesario asegurarse de que cada dato almacene dos punteros siguiente y anterior. siguiente apunta al siguiente nodo, anterior apunta al nodo anterior
  2. Liderando: El nodo principal con un bit centinela está a la cabeza de los datos.
  3. Ciclo: El siguiente nodo del nodo de cola apunta al nodo de cabeza del bit centinela, y el nodo anterior del bit centinela apunta al nodo de cola, formando un ciclo.

El texto comienza:

2. Trabajo necesario

2.1 Crear una estructura de lista doblemente enlazada

Debido a que es una lista doblemente enlazada, debe haber dos punteros en la estructura, uno next apunta al siguiente nodo y uno prev apunta al nodo anterior.

  • Archivo lista.h:
//创建双向链表结构
typedef int LTDataType;   //方便后续更改数据类型,本文以int整型为主
typedef struct ListNode
{
	LTDataType data; //存储数据
	struct ListNode* next; //指向下一个
	struct ListNode* prev; //指向上一个
}LTNode; //方便后续使用,不需要重复些struct

2.2, inicializar la lista enlazada

  • Ideas:

La dirección debe pasarse durante la inicialización, porque el cambio del parámetro formal no afectará al parámetro real, y el cambio de pphead no afectará a pList. Para pasar la dirección de pList, utilice **pphead para recibirla. esta vez, se requiere la aserción de afirmación, porque dos La dirección del puntero de nivel no puede ser nula. Debido a que es una lista enlazada doblemente circular, tanto el siguiente como el anterior del nodo centinela creado deben apuntar a sí mismo.

  • Archivo lista.h: (1)
//初始化链表(二级指针版)
void ListInit(LTNode* pphead);
  • Archivo list.c: (1)
//初始化链表(二级指针版)
void ListInit(LTNode** pphead)
{
	//传二级指针,那么当然要断言
	assert(pphead);
	*pphead = BuyLTNode(0);//因为是带哨兵位的头节点,所以一开始就要给一个节点
	//为了循环,要让哨兵位的next和prev均指向自己
	(*pphead)->next = *pphead; //注意优先级,*pphead要加括号
	(*pphead)->prev = *pphead;
}
  • Darse cuenta:

En el método anterior, pasamos un puntero de segundo nivel. ¿Podemos pasar un puntero de primer nivel? De hecho, también es posible. Simplemente escriba una función para devolver el puntero.

  • Archivo lista.h: (2)
//初始化链表(一级指针版本)
LTNode* ListInit();
  • Archivo lista.c: (2)
//初始化链表(一级指针版)
LTNode* ListInit()
{
	LTNode* phead = BuyLTNode(0);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

2.3 Nodo de aplicación dinámica

  • Archivo list.c:
//创建新节点
LTNode* BuyLTNode(LTDataType x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode; //返回新创建的节点
}

2.4, imprimir lista enlazada

  • Ideas:

Ya que está imprimiendo, lo primero que debe entender es que el bit centinela no se usa para almacenar datos válidos, por lo que no es necesario imprimir, defina un puntero cur para iterar, luego debería comenzar a imprimir desde el siguiente phead, y cuando termine el cur, volver a parar cuando phead

  • Archivo lista.h:
//打印链表
void ListPrint(LTNode* phead);
  • Archivo list.c:
//打印链表
void ListPrint(LTNode* phead)
{
	assert(phead);//断言
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

2.5 Destruir la lista enlazada

  • Ideas:

Dado que la lista enlazada se destruye, es natural destruir todos los elementos de la lista enlazada, incluido el bit centinela, pero después de todo, no puede estar vacío cuando se pasa por primera vez el phead, por lo que se debe afirmar que después de que se destruyan todos los datos válidos , el último Destroy the Sentinel.

Método 1: transversal

Defina un puntero cur, comience libre desde los primeros datos válidos del siguiente phead, guarde el siguiente, luego libre y atraviese a su vez

Método 2: adjuntar la función ListErase

Este método también es posible, pero cada vez que finalice el borrado, los dos nodos anteriores y posteriores se vincularán nuevamente. Aunque al final serán destruidos, el pato no necesita hacer esto, y es mejor usar el método 1 directamente.

  • Archivo lista.h:
//销毁链表
void ListDestory(LTNode* phead);
  • Archivo list.c:
//销毁链表
void ListDestory(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	//销毁从第一个节点到尾部的数据
	while (cur != phead)
	{
		LTNode* next = cur->next;
		//ListErase(cur);
		free(cur);
		cur = next;
	}
	//置空哨兵位节点phead
	free(phead);
	phead = NULL;
}
  • Archivo de prueba.c:
void TestList7()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数字
	}
	ListPrint(pList);//打印
	//销毁链表
	ListDestory(pList);
	pList = NULL;
}

3. Funciones principales

3.1 Insertar datos antes del nodo pos

  • Ideas:

Supongamos que ya hemos insertado 4 números, y ahora queremos insertar 30 delante del número 3, entonces primero debemos verificar si hay un número 3 y, de ser así, insertarlo. Nota: La función de búsqueda mencionada más adelante debe usarse aquí, que se cita directamente aquí, y la explicación detallada se puede ver más adelante, ¡el problema no es grande!

Primero, coloque 30 en el nodo recién creado newnode Para lograr la bidireccionalidad, primero apunte el siguiente de los datos anteriores 2 de 3 al nuevo nodo newnode, apunte el anterior de newnode a 2, el siguiente de newnode al punto 3, y el anterior de 3 para apuntar a newnode.

  •  Archivo lista.h:
//在pos前插入数据
void ListInsert(LTNode* pos, LTDataType x);
  • Archivo list.c:
//在pos前插入数据
void ListInsert(LTNode* pos, LTDataType x)
{
	assert(pos);
	//创建插入数据的新节点
	LTNode* newnode = BuyLTNode(x);
	//链接左侧
	pos->prev->next = newnode;
	newnode->prev = pos->prev;
	//链接右侧
	newnode->next = pos;
	pos->prev = newnode;
}
  • Archivo de prueba.c:
void TestList3()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数据
	}
	ListPrint(pList);//打印尾插的7个
	//寻找数字
	LTNode* pos = ListFind(pList, 3);
	if (pos)
	{
		ListInsert(pos, 30); //找到数字3就插入
	}
	ListPrint(pList);//打印
}
  • El efecto es el siguiente:

tapón de cola

  • Ideas:

En primer lugar, debido a que esta lista vinculada es un nodo principal con un bit centinela, el nodo principal no debe estar vacío y se requiere la afirmación de afirmación al principio. En segundo lugar, la inserción de la cola de una lista enlazada simple necesita encontrar la cola, aunque también se requiere una lista doblemente enlazada, pero es muy simple y no hay necesidad de atravesar la lista enlazada, porque el último nodo de la phead de la El nodo de cabeza centinela apunta a la cola, lo que refleja completamente el ciclo bidireccional. La ventaja es que si encuentra el nodo de cola, necesita crear otro nodo para almacenar los datos insertados, lo cual es conveniente para la inserción de la cola.

  • Archivo lista.h:
//尾插
void ListPushBack(LTNode* phead, LTDataType x);

  • Archivo list.c: 1.0
//尾插1.0
void ListPushBack(LTNode* phead, LTDataType x)
{
	assert(phead); //断言,防止头节点为空
	LTNode* tail = phead->prev; //找到尾节点,便于后续插入数据
	LTNode* newnode = BuyLTNode(x);//创建新节点
	//将此新插入的尾节点与上一个节点链接起来
	tail->next = newnode;
	newnode->prev = tail;
	//将尾节点与哨兵位phead链接起来构成循环
	newnode->next = phead;
	phead->prev = newnode;
}
  • Archivo de prueba.c:
void TestList1()
{
	//初始化(法一)
	/*LTNode* pList = NULL;
	ListInit(&pList);*/
	//初始化(法二)
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数据
	}
	ListPrint(pList);//打印尾插的7个
}
  • El efecto es el siguiente:

  • Darse cuenta:

En lo anterior, aprendimos a insertar datos antes de pos, luego imagina que cuando pos es igual a phead, ¿no es el frente (phead) la cola de la lista enlazada? Entonces, como debería ser, la inserción de la cola también puede ser hecho así:

  • Archivo list.c: 2.0
//尾插2.0
void ListPushBack(LTNode* phead, LTDataType x)
{
	assert(phead); 
	ListInsert(phead, x);
}

enchufe de cabeza

  • Ideas:

Ya hemos aprendido a insertar datos antes de pos, por lo que la implementación de la inserción de encabezado es particularmente simple. Cuando pos es el primer dato original phead->siguiente, los datos se insertan antes que él, luego la implementación pronto será el encabezado. , como sigue:

  • Archivo lista.h:
//头插
void ListPushFront(LTNode* phead, LTDataType x);
  • Archivo list.c:
//头插
void ListPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);
	ListInsert(phead->next, x);
}
  • Archivo de prueba.c:
void TestList4()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数字
	}
	ListPrint(pList);//打印
	for (int i = -2; i <= 0; i++)
	{
		ListPushFront(pList, i); //头插3个数字
	}
	ListPrint(pList);//打印
}
  • El efecto es el siguiente:

3.2 Eliminar datos de nodo en pos

  • Ideas:

Borrar los datos en la posición es realmente muy simple, un poco similar a la idea de ignorar directamente la posición o pasarla por alto. En primer lugar, debe encontrar el nodo anterior anterior y el siguiente nodo siguiente de pos, vincular anterior y uno al lado del otro, y omitir pos directamente, para que se puedan eliminar los datos del nodo en pos, recuerde liberar pos para liberar Aquí tomamos pos como 2 ejemplo:

  •  Archivo lista.h:
//删除pos处数据
void ListErase(LTNode* pos);
  • Archivo list.c:
//删除pos处数据
void ListErase(LTNode* pos)
{
	assert(pos);
	//定义两个指针保存pos两边的节点
	LTNode* prev = pos->prev;
	LTNode* next = pos->next;
	//将prev和next链接起来
	prev->next = next;
	next->prev = prev;
	//free释放
	free(pos);
	pos = NULL;
}
  • Archivo de prueba.c:
void TestList5()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数据
	}
	ListPrint(pList);//打印尾插的7个
	//寻找数字
	LTNode* pos = ListFind(pList, 3);
	if (pos)
	{
		ListErase(pos); //删除pos处数据
		pos = NULL; //形参的改变不会影响实参,最好在这置空pos
	}
	ListPrint(pList);//打印
}
  • El efecto es el siguiente:

eliminación de la cola

  • Ideas:

Se reflejarán nuevamente las características de la lista enlazada doblemente circular, de acuerdo a sus características sabemos que el prev de phead apunta al nodo tail, el cual se guarda con el tail pointer, y luego se define un puntero tailPrev para apuntar al prev de la cola Ahora solo tenemos que apuntar el siguiente de tailPrev al nodo centinela phead , y luego restablecer el anterior del bit centinela phead a tailPrev, pero no olvide liberar el nodo de cola eliminado para liberarlo (tail) . Recuerde afirmar que la lista enlazada no puede estar vacía, porque el ganglio centinela no se puede eliminar.

  • Archivo List.H:
//尾删
void ListPopBack(LTNode* phead);
  • Archivo list.c: 1.0
//尾删
void ListPopBack(LTNode* phead)
{
	assert(phead);//本身就有哨兵位,不能为空,要断言
	assert(phead->next != phead); //防止链表为空,导致删除哨兵位节点
	LTNode* tail = phead->prev;
	LTNode* tailPrev = tail->prev;
	//释放尾节点
	free(tail);
	tail = NULL;
	//将链表循环起来
	tailPrev->next = phead;
	phead->prev = tailPrev;
}
  • Archivo de prueba.c:
void TestList2()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数据
	}
	ListPrint(pList);//打印尾插的7个
	//尾删两次
	ListPopBack(pList);
	ListPopBack(pList);
	ListPrint(pList);//再次打印
}
  • El efecto es el siguiente:

  •  Darse cuenta:

En el artículo anterior, aprendimos a eliminar los datos del nodo en pos, luego, cuando pos es phead->prev, ¿es el nodo final el que se elimina? Por lo tanto, la eliminación final debe escribirse así:

  • Archivo list.c: 2.0
//尾删
void ListPopBack(LTNode* phead)
{
	assert(phead);//本身就有哨兵位,不能为空,要断言
	assert(phead->next != phead); //防止链表为空,导致删除哨兵位节点
	ListErase(phead->prev);
}

eliminación de encabezado

  • Ideas:

Con las lecciones anteriores, podemos usar directamente la función escrita anteriormente para eliminar los datos en pos para completar. Cuando pos es phead->prev, la posición de pos es la cola, y la cola se elimina en este momento. Por supuesto, se debe tener en cuenta que se requieren aserciones de afirmación adicionales para evitar que los datos eliminados se conviertan en nodos centinela.

  • Archivo lista.h:
//头删
void ListPopFront(LTNode* phead);
  • Archivo list.c:
//头删
void ListPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead); //防止删除哨兵位节点
	ListErase(phead->next);
}
  • Archivo de prueba.c:
void TestList6()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数字
	}
	ListPrint(pList);//打印
	//头插3个数字
	ListPushFront(pList, 0);
	ListPushFront(pList, -1);
	ListPushFront(pList, -2);
	ListPrint(pList);//打印
	//尾删3个数字
	ListPopBack(pList);
	ListPopBack(pList);
	ListPopBack(pList);
	ListPrint(pList);//打印
	//头删3个数字
	ListPopFront(pList);
	ListPopFront(pList);
	ListPopFront(pList);
	ListPrint(pList);//打印
}
  • El efecto es el siguiente:

3.3 Buscar datos

  • Ideas:

En realidad, encontrar datos es relativamente simple. Primero, defina un puntero cur para apuntar al siguiente bit centinela phead, recorra cur a su vez para ver si cur->data es el dato buscado x, si es así, devuelva cur, de lo contrario continúe ( cur=cur-> siguiente), o NULL si no se encuentra.

  • Archivo lista.h:
//链表查找
LTNode* ListFind(LTNode* phead, LTDataType x);
  • Archivo list.c:
//链表查找
LTNode* ListFind(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur; //找到就返回cur
		}
		cur = cur->next;
	}
	return NULL; //找不到就返回空
}

Cuarto, el código total

Archivo lista.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
//创建双向链表结构
typedef int LTDataType;   //方便后续更改数据类型,本文以int整型为主
typedef struct ListNode
{
	LTDataType data; //存储数据
	struct ListNode* next; //指向下一个
	struct ListNode* prev; //指向上一个
}LTNode; //方便后续使用,不需要重复些struct

//初始化链表(二级指针版本)
/*void ListInit(LTNode** pphead);*/
//初始化链表(一级指针版本)
LTNode* ListInit();

//打印链表
void ListPrint(LTNode* phead);
//链表查找
LTNode* ListFind(LTNode* phead, LTDataType x);
//销毁链表
void ListDestory(LTNode* phead);

//尾插
void ListPushBack(LTNode* phead, LTDataType x);
//尾删
void ListPopBack(LTNode* phead);
//头插
void ListPushFront(LTNode* phead, LTDataType x);
//头删
void ListPopFront(LTNode* phead);

//在pos前插入数据
void ListInsert(LTNode* pos, LTDataType x);
//删除pos处数据
void ListErase(LTNode* pos);

Archivo lista.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
//创建新节点
LTNode* BuyLTNode(LTDataType x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode; //返回新创建的节点
}
//初始化链表(二级指针版)
/*void ListInit(LTNode** pphead)
{
	//传二级指针,那么当然要断言
	assert(pphead);
	*pphead = BuyLTNode(0);//因为是带哨兵位的头节点,所以一开始就要给一个节点
	//为了循环,要让哨兵位的next和prev均指向自己
	(*pphead)->next = *pphead; //注意优先级,*pphead要加括号
	(*pphead)->prev = *pphead;
}*/
//初始化链表(一级指针版)
LTNode* ListInit()
{
	LTNode* phead = BuyLTNode(0);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

//打印链表
void ListPrint(LTNode* phead)
{
	assert(phead);//断言
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}
//链表查找
LTNode* ListFind(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur; //找到就返回cur
		}
		cur = cur->next;
	}
	return NULL; //找不到就返回空
}
//销毁链表
void ListDestory(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	//销毁从第一个节点到尾部的数据
	while (cur != phead)
	{
		LTNode* next = cur->next;
		//ListErase(cur);
		free(cur);
		cur = next;
	}
	//置空哨兵位节点phead
	free(phead);
	phead = NULL;
}

//尾插
void ListPushBack(LTNode* phead, LTDataType x)
{
	assert(phead); //断言,防止头节点为空
	/*
	法一:
	LTNode* tail = phead->prev; //找到尾节点,便于后续插入数据
	LTNode* newnode = BuyLTNode(x);//创建新节点
	//将此新插入的尾节点与上一个节点链接起来
	tail->next = newnode;
	newnode->prev = tail;
	//将尾节点与哨兵位phead链接起来构成循环
	newnode->next = phead;
	phead->prev = newnode;
	*/
	//法二:
	ListInsert(phead, x);
}
//尾删
void ListPopBack(LTNode* phead)
{
	assert(phead);//本身就有哨兵位,不能为空,要断言
	assert(phead->next != phead); //防止链表为空,导致删除哨兵位节点
	/*
	法一:
	LTNode* tail = phead->prev;
	LTNode* tailPrev = tail->prev;
	//释放尾节点
	free(tail);
	tail = NULL;
	//将链表循环起来
	tailPrev->next = phead;
	phead->prev = tailPrev;
	*/
	//法二:
	ListErase(phead->prev);
}

//头插
void ListPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);
	ListInsert(phead->next, x);
}
//头删
void ListPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead); //防止删除哨兵位节点
	ListErase(phead->next);
}

//在pos前插入数据
void ListInsert(LTNode* pos, LTDataType x)
{
	assert(pos);
	//创建插入数据的新节点
	LTNode* newnode = BuyLTNode(x);
	//链接左侧
	pos->prev->next = newnode;
	newnode->prev = pos->prev;
	//链接右侧
	newnode->next = pos;
	pos->prev = newnode;
}
//删除pos处数据
void ListErase(LTNode* pos)
{
	assert(pos);
	//定义两个指针保存pos两边的节点
	LTNode* prev = pos->prev;
	LTNode* next = pos->next;
	//将prev和next链接起来
	prev->next = next;
	next->prev = prev;
	//free释放
	free(pos);
	pos = NULL;
}

Archivo de prueba.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
void TestList1()
{
	//初始化(法一)
	/*LTNode* pList = NULL;
	ListInit(&pList);*/
	//初始化(法二)
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数据
	}
	ListPrint(pList);//打印尾插的7个
}

void TestList2()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数据
	}
	ListPrint(pList);//打印尾插的7个
	//尾删两次
	ListPopBack(pList);
	ListPopBack(pList);
	ListPrint(pList);//再次打印
}

void TestList3()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数据
	}
	ListPrint(pList);//打印尾插的7个
	//寻找数字
	LTNode* pos = ListFind(pList, 3);
	if (pos)
	{
		ListInsert(pos, 30); //找到数字3就插入
	}
	ListPrint(pList);//打印
}

void TestList4()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数字
	}
	ListPrint(pList);//打印
	for (int i = -2; i <= 0; i++)
	{
		ListPushFront(pList, i); //头插3个数字
	}
	ListPrint(pList);//打印
}

void TestList5()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数据
	}
	ListPrint(pList);//打印尾插的7个
	//寻找数字
	LTNode* pos = ListFind(pList, 3);
	if (pos)
	{
		ListErase(pos); //删除pos处数据
		pos = NULL; //形参的改变不会影响实参,最好在这置空pos
	}
	ListPrint(pList);//打印
}

void TestList6()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数字
	}
	ListPrint(pList);//打印
	//头插3个数字
	ListPushFront(pList, 0);
	ListPushFront(pList, -1);
	ListPushFront(pList, -2);
	ListPrint(pList);//打印
	//尾删3个数字
	ListPopBack(pList);
	ListPopBack(pList);
	ListPopBack(pList);
	ListPrint(pList);//打印
	//头删3个数字
	ListPopFront(pList);
	ListPopFront(pList);
	ListPopFront(pList);
	ListPrint(pList);//打印
	//销毁链表
	ListDestory(pList);
	pList = NULL;
}

void TestList7()
{
	LTNode* pList = ListInit();
	for (int i = 1; i <= 7; i++)
	{
		ListPushBack(pList, i); //尾插7个数字
	}
	ListPrint(pList);//打印
	//销毁链表
	ListDestory(pList);
	pList = NULL;
}
int main()
{
	//TestList1();
	//TestList2();
	//TestList3();
	//TestList4();
	//TestList5();
	//TestList6();
	TestList7();
	return 0;
}

5. Expansión: Lista de secuencias de contraste y Lista enlazada

diferencia tabla de secuencia lista enlazada
Espacio de almacenamiento Físicamente debe ser continuo Lógicamente contiguos, pero no necesariamente físicamente contiguos
acceso aleatorio Apoyo O(1) O(N) no es compatible
Insertar o eliminar elementos en cualquier lugar Puede necesitar mover elementos, ineficiente O(N) Simplemente modifique el puntero para que apunte a
insertar Tabla de secuencia dinámica, necesita expandirse cuando el espacio no es suficiente sin concepto de capacidad
Escenarios de aplicación Los elementos se almacenan de manera eficiente + se accede con frecuencia Insertar y eliminar datos en cualquier lugar
utilización de caché alto Bajo
  • Comparación de ventajas y desventajas:
tabla de secuencia lista enlazada
ventaja

1. El espacio físico es continuo, lo cual es conveniente para el acceso aleatorio con subíndices.

2. La tasa de aciertos de la memoria caché de la CPU será mayor. (Reponer)

1. Solicitar espacio gratuito bajo demanda.

2. Los datos se pueden insertar y eliminar en O(1) en cualquier posición.

defecto

1. Solo porque el espacio físico es continuo, el espacio no es suficiente para necesitar expansión, y la expansión en sí debe consumirse.En segundo lugar, todavía hay una cierta cantidad de desperdicio de espacio en el mecanismo de expansión.

2. Insertar y eliminar en la cabeza o en el medio, mover datos, baja eficiencia, O(N).

1. No se admite el acceso aleatorio de subíndices.

2. Algunos algoritmos no son adecuados para ello, como la búsqueda binaria, la clasificación, etc.

Supongo que te gusta

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