DS005 Estructura de datos: investigación sobre los principios de implementación de una lista vinculada única: un ejemplo del libro de texto del maestro Yan Weimin

1. La tabla de secuencia es tan buena, ¿por qué necesita una lista vinculada?

Desventajas de la tabla de secuencia:

• Además del final de la lista, insertar y borrar elementos en la tabla de secuencia requiere mover otros elementos, lo cual es ineficiente, la complejidad de tiempo promedio es O (n).

• La tabla de secuencia necesita espacio continuo.Cuando la cantidad de datos es relativamente grande, si no hay suficiente espacio continuo, la tabla de secuencia fallará. !

 

Para solucionar esta deficiencia, se diseña una lista enlazada. La inserción y eliminación de la lista vinculada no necesita mover otros elementos y la eficiencia de la inserción y eliminación es alta, pero se pierde la ventaja del acceso aleatorio.

 

Otro: ¡esta es una innovación disruptiva, comenzar de nuevo, no reparar en el marco del almacenamiento secuencial! !

La lista enlazada simple es la estructura de cadena más simple. A partir de esta divergencia y extensión, se pueden construir estructuras más complejas, como árboles y gráficos.

La base no es sólida, el suelo tiembla y la lista vinculada debe aprenderse bien.

En segundo lugar, la definición de lista enlazada individualmente

• Una lista enlazada individual conecta datos de secuencia como una "cadena" almacenando las direcciones de los nodos subsiguientes en el nodo actual, por lo que se denomina lista enlazada.

• El "único" de la lista enlazada individualmente significa que sólo se almacenan datos de una dirección en el nodo actual, es decir, la dirección del nodo de datos siguiente.

Tres, la forma de nodo de la lista enlazada individualmente

Cuarto, la forma general de la lista enlazada individualmente

 

 

La configuración del nodo principal en la lista enlazada individualmente es para facilitar la inserción y eliminación de nodos en la cabecera de la lista enlazada.

      El nodo principal y el nodo de datos de la lista enlazada individual de la que hablamos en esta sección son del mismo tipo.

       A veces, por conveniencia, se puede establecer en el nodo principal un puntero al encabezado de la lista vinculada, un puntero al final de la lista vinculada y un número entero que represente la longitud de la lista vinculada. En este momento, el tipo de nodo principal es diferente del tipo de nodo de lista vinculado.

Los archivos de encabezado y las constantes de símbolo que se utilizan en los siguientes programas son los siguientes:

#include <iostream>
usando el espacio de nombres std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status; 
// Status es el tipo de valor de retorno de la función, y su valor es el código de estado del resultado de la función.
typedef int ElemType; 
// ElemType es un tipo de datos definible, se establece en int type

 

Cinco, la descripción de C ++ del nodo de lista enlazada

typedef struct LNode {     ElemType data; // El campo de datos del nodo     struct LNode * next; // El campo de puntero del nodo } LNode, * LinkList; // LinkList es el tipo de puntero a la estructura LNode


De esta manera, head es el puntero principal y length registra el número de nodos de elementos en la lista vinculada, excluyendo el nodo principal.

Seis, genera un nodo    

LNode *CreateNode(ElemType e)
{//为元素e生成一个结点
	LNode *t=new LNode;
	if(t==0) return 0;
	t->data=e;
	t->next=0;
	return t; 
}

Utilice el nuevo operador para solicitar espacio de tipo de nodo desde el sistema operativo.

Si el sistema operativo dice que no soy rico y lo rechaza, devuelve 0, que es un puntero nulo; de lo contrario, devuelve la dirección del nuevo nodo. 

Siete, inicialización

Al principio, se genera y se implementa un nodo principal en el constructor.

Status InitList(LinkList &L) 
{ //算法2.6 单链表的初始化
	//构造一个空的单链表L
	L = CreateNode(0);
	if(L==0) return ERROR;
	return OK;
}

head es una variable que almacena la dirección, que es la dirección del nodo principal, que no tiene nombre. 

 

8. Insertar un elemento después de cierto nodo.

void insert(LNode* p, LNode* q)
{//p是链表中某个结点的指针,q是一个新结点的指针
	//将q插入到p的后面
	q->next = p->next;
	p->next = q;
}

void insert(LNode* p, ElemType x)
{//在指针p所指的结点后面插入x
	LNode* q, * t;

	t = CreateNode(x);
	insert(p, t);		

}

La sobrecarga de funciones de C ++ tiene el mismo nombre de función pero diferentes parámetros. 

Inserte el nodo q después del nodo p. No debe desconectar primero el puntero después de p. Antes de desconectar, debe haber un puntero al nodo después del p original.

De lo contrario, el nodo se perderá.

Nueve, inserte elementos después del nodo principal

void push_head(LinkList &L, ElemType e)
{//在头结点后面插入数据
	insert(L,e) ;	
}

Con el presagio de la función de inserción anterior, la operación de insertar un nodo en la cabeza es tan simple.

10. Inserte un nodo al final de la lista vinculada.

 

void push_back(LinkList &L, ElemType e)
{//在头结点后面插入数据
	LNode *p=L;
	while(p->next) 
	{
		p=p->next; 
	} 
	insert(p,e) ;	
}

 Primero busque el nodo final de la lista vinculada, apúntelo con el puntero p, y luego inserte los datos después de p.

11. Obtenga la dirección del i-ésimo nodo

LNode *Locate_i(LinkList &L,int i)
{//查找 第i个结点,用指针指向它,并返回该指针
	if(i<0) return 0;//不合法 
	if(i==0)return L;//把头结点看做0号结点 
	LNode *p=L->next;
	int j=1;
	while(j<i && p)
	{
		p=p->next;
		j++; 
	}
	return p;
}

Encontrar el i-ésimo nodo en la lista enlazada individualmente es una operación básica. 

12. Insertar datos antes del i-ésimo nodo

Status ListInsert(LinkList &L, int i, ElemType e) 
{ //算法2.9 单链表的插入
	//在带头结点的单链表L中第i个位置插入值为e的新结点
	LNode *p=Locate_i(L,i-1);//寻找第i-1个位置 
	if(p==0) return ERROR;//找不到插入位置 
	LNode *t=CreateNode(e);//为e生成结点 
	t->next=p->next;
	p->next=t; 
	return OK;
} 

Para insertar datos en el i-ésimo nodo, inserte los datos después del i-1 ° nodo, y primero debe encontrar el i-1 ° nodo.

13. Eliminar el i-ésimo nodo

Status ListDelete(LinkList &L, int i) 
{ //算法2.9 单链表的删除
	//在带头结点的单链表L中,删除第i个位置	
	LinkList p, q;
	p=Locate_i(L,i-1);//找到第i-1个结点
	if(p==0) return ERROR; 
	q = p->next; //临时保存被删结点的地址以备释放 
	if(q==0) return ERROR;
	p->next = q->next; //改变删除结点前驱结点的指针域 
	delete q; //释放删除结点的空间 
	
	return OK;
}

Para eliminar el i-ésimo nodo, primero debe encontrar el i-1 ° nodo. 

14. Buscar en la lista vinculada

 


LNode *LocateElem(LinkList L, int e) 
{ //算法2.8 按值查找
	//在带头结点的单链表L中查找值为e的元素
	LinkList p = L->next;
	//顺链域向后扫描,直到p为空或p所指结点的数据域等于e
	while (p)
	{
		if(p->data==e)
			return p;//查找成功 
		p=p->next;
	}	
	return 0; //查找失败 
}

15. Libere el espacio ocupado por la lista enlazada individualmente

Implementado en el destructor

void freeAll(LinkList &L)
{//释放所有结点空间
	LNode* p;	
	while (L->next)
	{
		p = L->next;
		L->next = p->next;
		delete p;
	}
	delete L;
	L = 0;	
}

16. Código completo

 

#include<iostream>
using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status; 
//Status 是函数返回值类型,其值是函数结果状态代码。
typedef int ElemType; 
//ElemType 为可定义的数据类型,此设为int类型

typedef struct LNode {
	ElemType data; //结点的数据域
	struct LNode *next; //结点的指针域
} LNode, *LinkList; //LinkList为指向结构体LNode的指针类型


LNode *CreateNode(ElemType e)
{//为元素e生成一个结点
	LNode *t=new LNode;
	if(t==0) return 0;
	t->data=e;
	t->next=0;
	return t; 
}

Status InitList(LinkList &L) 
{ //算法2.6 单链表的初始化
	//构造一个空的单链表L
	L = CreateNode(0);
	if(L==0) return ERROR;
	return OK;
}

void insert(LNode* p, LNode* q)
{//p是链表中某个结点的指针,q是一个新结点的指针
	//将q插入到p的后面
	q->next = p->next;
	p->next = q;
}

void insert(LNode* p, ElemType x)
{//在指针p所指的结点后面插入x
	LNode* q, * t;

	t = CreateNode(x);
	insert(p, t);		

}

void push_head(LinkList &L, ElemType e)
{//在头结点后面插入数据
	insert(L,e) ;	
}

void push_back(LinkList &L, ElemType e)
{//在头结点后面插入数据
	LNode *p=L;
	while(p->next) 
	{
		p=p->next; 
	} 
	insert(p,e) ;	
}

LNode *Locate_i(LinkList &L,int i)
{//查找 第i个结点,用指针指向它,并返回该指针
	if(i<0) return 0;//不合法 
	if(i==0)return L;//把头结点看做0号结点 
	LNode *p=L->next;
	int j=1;
	while(j<i && p)
	{
		p=p->next;
		j++; 
	}
	return p;
}


Status ListInsert(LinkList &L, int i, ElemType e) 
{ //算法2.9 单链表的插入
	//在带头结点的单链表L中第i个位置插入值为e的新结点
	LNode *p=Locate_i(L,i-1);//寻找第i-1个位置 
	if(p==0) return ERROR;//找不到插入位置 
	LNode *t=CreateNode(e);//为e生成结点 
	t->next=p->next;
	p->next=t; 
	return OK;
} 


Status GetElem(LinkList L, int i, ElemType &e)
 { //算法2.7 单链表的取值
	//在带头结点的单链表L中查找第i个元素
	//用e返回L中第i个数据元素的值
	LNode *p=Locate_i(L,i);
	if(p==0) return ERROR;//i不合法 
	e = p->data; //取第i个结点的数据域
	return OK;
} 


LNode *LocateElem(LinkList L, int e) 
{ //算法2.8 按值查找
	//在带头结点的单链表L中查找值为e的元素
	LinkList p = L->next;
	//顺链域向后扫描,直到p为空或p所指结点的数据域等于e
	while (p)
	{
		if(p->data==e)
			return p;//查找成功 
		p=p->next;
	}	
	return 0; //查找失败 
}

Status ListDelete(LinkList &L, int i) 
{ //算法2.9 单链表的删除
	//在带头结点的单链表L中,删除第i个位置	
	LinkList p, q;
	p=Locate_i(L,i-1);//找到第i-1个结点
	if(p==0) return ERROR; 
	q = p->next; //临时保存被删结点的地址以备释放 
	if(q==0) return ERROR;
	p->next = q->next; //改变删除结点前驱结点的指针域 
	delete q; //释放删除结点的空间 
	
	return OK;
}

void freeAll(LinkList &L)
{//释放所有结点空间
	LNode* p;	
	while (L->next)
	{
		p = L->next;
		L->next = p->next;
		delete p;
	}
	delete L;
	L = 0;	
}

void print(LinkList &L)
{
	if(L==0)
		cout<<"链表没有头结点"<<endl;
	LNode *p=L->next;
	while(p)
	{
		cout<<p->data<<" ";
		p=p->next;
	}
	cout<<"\n";
}

int main()
{
	LNode *H;
	InitList(H);
	push_head(H,1);
	print(H);
	push_head(H,3);
	print(H);
	push_head(H,5);
	print(H);
	
	push_back(H,6);push_back(H,7);push_back(H,8);
	print(H);
	 
	
	int x;
	GetElem(H,2,x);
	cout<<x<<endl;
	
	LNode *p=LocateElem(H,3);
	cout<<p->data<<endl;
	
	print(H);
	
	ListDelete(H,3);
	print(H);
	
		
	ListInsert(H,1,1);
	print(H);
	ListInsert(H,2,2);
	print(H);
	ListInsert(H,3,3);
	print(H);
	ListInsert(H,4,4);
	print(H);
	freeAll(H);
	print(H);
	
	
	return 0;
}

17. Ejecución de resultados

 

Supongo que te gusta

Origin blog.csdn.net/weixin_43917370/article/details/108688559
Recomendado
Clasificación