Salvador de estructura de datos [Tabla de secuencia--2]

contenido

1. Tabla lineal (la tabla secuencial es un tipo de tabla lineal)

2. Implementación de la tabla de secuencia

2.2 Estructura de la tabla de secuencias

2.3 Funciones de interfaz

2.4 Implementación de la función de expansión

2.5 Tabla de secuencia de inicialización

2.6 Insertar datos desde el final de la tabla de secuencia

2.7 Eliminar datos del final de la tabla de secuencia

2.8 Insertar datos desde el encabezado de la tabla de secuencia

2.9 Eliminar datos del encabezado de la tabla de secuencia

2.10 Consulta de tabla de secuencias, retorno de subíndice

2.11 La tabla de secuencia inserta x en la posición pos

2.12 La tabla de secuencia elimina el valor en la posición pos.

2.13 Tabla de secuencia de destrucción

3. Código completo de tabla de secuencia

SLachieve.h

SLachieve.c

prueba.c


1. Tabla lineal (la tabla secuencial es un tipo de tabla lineal)

Una lista lineal es una secuencia finita de n elementos de datos con las mismas características. La lista lineal es una estructura de datos ampliamente utilizada en la práctica, lista lineal común: lista de secuencias, lista enlazada, pila, cola, cadena...

Una tabla lineal es lógicamente una estructura lineal, es decir, una línea recta continua. Sin embargo, la estructura física no es necesariamente continua.Cuando una tabla lineal se almacena físicamente, generalmente se almacena en forma de matriz y estructura de cadena.


2. Implementación de la tabla de secuencia

La tabla de secuencia es una estructura lineal en la que los elementos de datos se almacenan secuencialmente en un segmento de unidades de almacenamiento con direcciones físicas consecutivas, generalmente utilizando almacenamiento en matriz. Complete la adición, eliminación, búsqueda y modificación de datos en la matriz. Lo que usamos hoy es una tabla de secuencia dinámica: use almacenamiento de matriz abierto dinámicamente (tamaño de espacio asignado dinámicamente según sea necesario)

SLachieve.c implementación de funciones
SLachieve.h declaración de función
prueba.c prueba de funcionamiento

Antes de escribir el código, necesitamos compilar varios archivos para implementar mejor la tabla de secuencias. Al mismo tiempo, para la solidez del código, debemos hacer lo siguiente:

1. Usa afirmar más

2. Comprobar los límites de la tabla de secuencias

3. Después de escribir una función, pruebe si hay un error a través de un ejemplo, que es fácil de modificar.


2.2 Estructura de la tabla de secuencias

typedef int SLDataType;//便于直接修改参数类型

typedef struct SeqList
{
	SLDataType* s1;//指向动态数组指针
	size_t sz;//数据个数
	size_t capacity;//容量
}SL;

 

2.3 Funciones de interfaz

void SeqListInit(SL* ps);//初始化顺序表
void SeqListDestory(SL* ps);//删除顺序表

void PrintSL(SL* ps);

void SeqListPushBack(SL* ps, SLDataType x);//从顺序表尾部插入数据
void SeqListPopBack(SL* ps);//从顺序表尾部删除数据

void SeqListPushFront(SL* ps, SLDataType x);//从顺序表头部插入数据
void SeqListPopFront(SL* ps);//从顺序表头部删除数据

int SeqListFind(SL* ps, SLDataType x);// 顺序表查找

void SeqListInsert(SL* ps, size_t pos, SLDataType x);// 顺序表在pos位置插入x
void SeqListErase(SL* ps, size_t pos);// 顺序表删除pos位置的值

2.4 Implementación de la función de expansión

Dado que estamos desarrollando espacio en la memoria dinámica, necesitamos usar realloc para abrir espacio (cuando realloc está abriendo espacio, si el puntero está vacío, su función es similar a malloc)

Precauciones:

1. Se debe usar el operador ternario para determinar si la capacidad está vacía en este momento. Si la capacidad está vacía, ábrala a 4 y luego use realloc para abrir la memoria dinámica.

2. El tamaño de cada expansión es el doble del tamaño original.Al mismo tiempo, se debe juzgar si la expansión es exitosa o no.

3. Asigne la dirección abierta al puntero de la tabla de secuencia

void CheckCapitcy(SL* ps)
{
	assert(ps);
	if (ps->capacity == ps->sz)
	{
		int NewCapitcy = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->s1, NewCapitcy * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("SLPushBack:realloc Error");
			return;
		}
		ps->s1 = tmp;
		ps->capacity = NewCapitcy;
	}
}

2.5 Tabla de secuencia de inicialización

Precauciones:

1. La tabla de secuencia debe inicializarse en test.c y la variable s1 debe crearse a través de SL

void SeqListInit(SL* ps)
{	
	ps->s1 = NULL;
	ps->capacity = ps->sz = 0;
}

2.6 Insertar datos desde el final de la tabla de secuencia

 Precauciones:

1. La capacidad debe verificarse cuando se usa

2. El número de datos aumentará con la inserción

void SeqListPushBack(SL* ps, SLDataType x)//从顺序表尾部插入数据
{
	assert(ps);
	CheckCapitcy(ps);
	
	ps->s1[ps->sz]= x;
	ps->sz++;
}

2.7 Eliminar datos del final de la tabla de secuencia

 Precauciones:

1. La cantidad de datos: eso es suficiente, se vuelve igual a eliminar (sobrescribir los datos originales al agregar)

void SeqListPopBack(SL* ps)//从顺序表尾部删除数据
{
	assert(ps);
	if (ps->sz > 0)
	{
		ps->sz--;
	}
}

2.8 Insertar datos desde el encabezado de la tabla de secuencia

 Precauciones:

1. La capacidad debe verificarse cuando se usa

2. Si hay datos en la tabla de secuencia, sobrescriba los datos de atrás hacia adelante, coloque los nuevos datos en primer lugar y la cantidad de datos al mismo tiempo ++

void SeqListPushFront(SL* ps, SLDataType x)//从顺序表头部插入数据
{
	assert(ps);
	CheckCapitcy(ps);
	for (int i = ps->sz; i > 0; i--)
	{
		ps->s1[i] = ps->s1[i - 1];
	}
	ps->s1[0] = x;
	ps->sz++;
}

2.9 Eliminar datos del encabezado de la tabla de secuencia

 Precauciones:

1. Puede sobrescribir directamente los datos originales y la cantidad de datos al mismo tiempo.

void SeqListPopFront(SL* ps)//从顺序表头部删除数据
{
	assert(ps);
	if (ps->sz > 0)
	{
		for (int i = 0; i < (ps->sz); i++)
		{
			ps->s1[i] = ps->s1[i + 1];
		}
	}
	ps->sz--;
}

2.10 Consulta de tabla de secuencias, retorno de subíndice

 Precauciones:

1. Regrese a la posición del subíndice después de encontrarlo

int SeqListFind(SL* ps,SLDataType x)// 顺序表查找,返回下标
{
	assert(ps);
	for (int i = 0; i < (ps->sz); i++)
	{
		if (ps->s1[i] == x )
		{
			return i;
		}
		
	}
	return -1;
}

2.11 La tabla de secuencia inserta x en la posición pos

 Precauciones:

1. La posición de inserción de pos debe ser menor que el número de datos, de lo contrario, viola las reglas de almacenamiento continuo en la tabla de secuencia

2. Comprueba la capacidad

3. Los datos se mueven hacia atrás, dejando espacio para insertar x y la cantidad de datos al mismo tiempo ++

void SeqListInsert(SL* ps, size_t pos, SLDataType x)//顺序表在pos位置插入x
{
	assert(ps);
	assert(ps->sz >= pos); //被插入的位置必须小于等于sz
	CheckCapitcy(ps);
	for (int i = ps->sz; i > pos; i--)
	{
		ps->s1[i] = ps->s1[i - 1];
	}
	ps->s1[pos] = x;
	ps->sz++;
}

2.12 La tabla de secuencia elimina el valor en la posición pos.

 Precauciones:

1. Debe haber elementos para eliminar

2. La cobertura de datos es equivalente a la eliminación

void SeqListErase(SL* ps, size_t pos)// 顺序表删除pos位置的值
{
	assert(ps->sz >0);//有元素可删除
	for (int i = pos; i<ps->sz; i++)
	{
		ps->s1[i] = ps->s1[i + 1];
	}
	ps->sz--;
}

2.13 Tabla de secuencia de destrucción

 Precauciones:

1. La memoria desarrollada dinámicamente debe liberarse

2. Establezca el puntero en NULL para evitar punteros salvajes

void SeqListDestory(SL* ps)//删除顺序表
{
	assert(ps);
	free(ps->s1);
	ps->s1 = NULL;
	ps->sz = ps->capacity = 0;
}

3. Código completo de tabla de secuencia

 

SLachieve.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1

typedef int SLDataType;

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct SeqList
{
	SLDataType* s1;//指向动态数组指针
	size_t sz;//数据个数
	size_t capacity;//容量
}SL;

void SeqListInit(SL* ps);//初始化顺序表
void SeqListDestory(SL* ps);//删除顺序表

void PrintSL(SL* ps);

 
void SeqListPushBack(SL* ps, SLDataType x);//从顺序表尾部插入数据
void SeqListPopBack(SL* ps);//从顺序表尾部删除数据

void SeqListPushFront(SL* ps, SLDataType x);//从顺序表头部插入数据
void SeqListPopFront(SL* ps);//从顺序表头部删除数据


int SeqListFind(SL* ps, SLDataType x);// 顺序表查找

void SeqListInsert(SL* ps, size_t pos, SLDataType x);// 顺序表在pos位置插入x
void SeqListErase(SL* ps, size_t pos);// 顺序表删除pos位置的值

SLachieve.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "SLachieve.h"

void CheckCapitcy(SL* ps)
{
	assert(ps);
	if (ps->capacity == ps->sz)
	{
		int NewCapitcy = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->s1, NewCapitcy * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("SLPushBack:realloc Error");
			return;
		}
		ps->s1 = tmp;
		ps->capacity = NewCapitcy;
	}
}


void SeqListInit(SL* ps)
{	
	ps->s1 = NULL;
	ps->capacity = ps->sz = 0;
}

void SeqListPushBack(SL* ps, SLDataType x)//从顺序表尾部插入数据
{
	assert(ps);
	CheckCapitcy(ps);
	
	ps->s1[ps->sz]= x;
	ps->sz++;
}

void SeqListPopBack(SL* ps)//从顺序表尾部删除数据
{
	assert(ps);
	if (ps->sz > 0)
	{
		ps->sz--;
	}
}

void SeqListPushFront(SL* ps, SLDataType x)//从顺序表头部插入数据
{
	assert(ps);
	CheckCapitcy(ps);
	for (int i = ps->sz; i > 0; i--)
	{
		ps->s1[i] = ps->s1[i - 1];
	}
	ps->s1[0] = x;
	ps->sz++;
}

void SeqListPopFront(SL* ps)//从顺序表头部删除数据
{
	assert(ps);
	if (ps->sz > 0)
	{
		for (int i = 0; i < (ps->sz); i++)
		{
			ps->s1[i] = ps->s1[i + 1];
		}
	}
	ps->sz--;
}



void PrintSL(SL* ps)
{
	for (int i = 0; i < (ps->sz); i++)
	{
		printf("%d ", ps->s1[i]);
	}
}

int SeqListFind(SL* ps,SLDataType x)// 顺序表查找,返回下标
{
	assert(ps);
	for (int i = 0; i < (ps->sz); i++)
	{
		if (ps->s1[i] == x )
		{
			return i;
		}
		
	}
	return -1;
}

void SeqListInsert(SL* ps, size_t pos, SLDataType x)//顺序表在pos位置插入x
{
	assert(ps);
	assert(ps->sz >= pos); //被插入的位置必须小于等于sz
	CheckCapitcy(ps);
	for (int i = ps->sz; i > pos; i--)
	{
		ps->s1[i] = ps->s1[i - 1];
	}
	ps->s1[pos] = x;
	ps->sz++;
}

void SeqListErase(SL* ps, size_t pos)// 顺序表删除pos位置的值
{
	assert(ps->sz >0);//有元素可删除
	for (int i = pos; i<ps->sz; i++)
	{
		ps->s1[i] = ps->s1[i + 1];
	}
	ps->sz--;
}

void SeqListDestory(SL* ps)//删除顺序表
{
	assert(ps);
	free(ps->s1);
	ps->s1 = NULL;
	ps->sz = ps->capacity = 0;
}

prueba.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "SLachieve.h"

void TestSL1()//测试尾插尾删
{
	SL s1;
	SeqListInit(&s1);

   SeqListPushBack(&s1, 3);
   SeqListPushBack(&s1, 2);
   SeqListPushBack(&s1, 1);
   SeqListPushBack(&s1, 1);
   SeqListPopBack(&s1);
   SeqListPopBack(&s1);
   SeqListPopBack(&s1);

   PrintSL(&s1);

}

//void TestSL2()//测试头插头删
//{
//	SL s1;
//	SeqListInit(&s1);
//
//
//	
//	SeqListPushFront(&s1,1);
//	SeqListPushFront(&s1, 2);
//	SeqListPushFront(&s1, 3);
//	SeqListPushFront(&s1, 4);
//	SeqListPushFront(&s1, 5);
//	SeqListPushFront(&s1,6);
//
//	SeqListPopFront(&s1);
//	SeqListPopFront(&s1);
//	SeqListPopFront(&s1);
//	SeqListPopFront(&s1);
//	SeqListPopFront(&s1);
//	SeqListPopFront(&s1);
//	
//
//	PrintSL(&s1);
//
//}

void TestSL3()//测试顺序表查找
{
	SL s1;
	SeqListInit(&s1);

	//SeqListPushFront(&s1, 1);
	//SeqListPushFront(&s1, 2);

	int ret = SeqListFind(&s1,2);
	if (ret >= 0)
	{
		printf("找到了");
	}
	else
		printf("没找到");

}



void TestSL4()//顺序表在pos位置插入,顺序表删除pos位置的值
{
	SL s1;
	SeqListInit(&s1);

	//SeqListPushBack(&s1, 1);
	//SeqListPushBack(&s1, 2);
	//SeqListPushBack(&s1, 3);
	//SeqListPushBack(&s1, 4);
	//PrintSL(&s1);
	//printf("\n");
	//SeqListInsert(&s1, 1, 3);
	//SeqListInsert(&s1, 1, 5);
	//PrintSL(&s1);
	//SeqListErase(&s1, 1);
	//printf("\n");
	//PrintSL(&s1);
}




int main()
{
	TestSL4();

	return 0;
}

4. Problema de la tabla de secuencias

1. Inserción y eliminación de medio/cabeza, la complejidad de tiempo es O(N)

2. Para aumentar la capacidad, debe solicitar un nuevo espacio, copiar datos y liberar espacio antiguo. Habrá algo de consumo.

3. La expansión de la capacidad es generalmente un aumento de 2 veces, y seguramente habrá una cierta cantidad de espacio desperdiciado. 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.

Así que presentamos el concepto de lista enlazada (próximo blog)

Supongo que te gusta

Origin blog.csdn.net/weixin_63543274/article/details/124306190
Recomendado
Clasificación