[Estructura de datos] Realización de la tabla de secuencia (tabla lineal)

Tabla de contenido

         1. ¿Qué es una tabla de secuencia?

         En segundo lugar, la realización dinámica de la tabla de secuencia

               1. Inicialización de la tabla de secuencias

               2. Impresión de tabla de secuencias

               3. Espacio de comprobación de la tabla de secuencias

               4. Inserción del extremo de la tabla de secuencias

               5. Eliminar al final de la lista de secuencias

               6. Conector de encabezado de secuencia

               7. Eliminar encabezado de secuencia

               8. Insertar en la posición especificada en la tabla de secuencia

               9. Eliminar la posición especificada en la tabla de secuencia

               10. Consulta de tabla de secuencias

               11. Destrucción de la tabla de secuencias

         3. Código fuente

               1、SeqList.h

               2, SeqList.c

               3, prueba.c

 


 

1. ¿Qué es una tabla de secuencia?

La tabla de secuencia es una estructura lineal en la que los elementos de datos se almacenan secuencialmente en una unidad de almacenamiento con direcciones físicas continuas y generalmente se almacenan en una matriz. Agregue, elimine, verifique y modifique datos en la matriz.

La tabla de secuencias está estructurada de la siguiente manera:

 

Las tablas de secuencias se dividen generalmente en dos tipos:

1. Tabla de secuencia estática: use una matriz de longitud fija para almacenar elementos.

#define Max 10 
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType data[Max];  //定长数组
	size_t size;  //有效数据的个数
}SeqList;

2. Tabla de secuencia dinámica: use almacenamiento de matriz desarrollado dinámicamente.

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;      // 指向动态开辟数组的指针
	size_t size;        // 有效数据个数
	size_t capicity;    // 容量空间的大小
}SeqList;

Este artículo utiliza principalmente la tabla de secuencia dinámica , porque la tabla de secuencia estática ha establecido el tamaño del espacio de la matriz de antemano, si el tamaño del espacio requerido es mayor que el tamaño preestablecido, se producirá un desbordamiento en este momento y es un inconveniente de usar , por lo que aquí se utiliza una tabla de secuencia dinámica para abrir tanto espacio de matriz como sea posible.

En segundo lugar, la realización dinámica de la tabla de secuencia

  1. Inicialización de la tabla de secuencias

//初始化
void SLInit(SL* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

Puede abrir espacio para la tabla de secuencias durante la inicialización y, por supuesto, puede establecer directamente el puntero a en NULL y establecer el tamaño y la capacidad en 0 también.

  2. Impresión de tabla de secuencias

//打印
void SLPrint(SL* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

  3. Espacio de comprobación de la tabla de secuencias

Al insertar y eliminar la tabla de secuencias, el tamaño del espacio de la tabla de secuencias estará involucrado. Al insertar, primero debe juzgar si el espacio está lleno. Si está lleno, debe continuar abriendo espacio antes de poder insertar.

void SLCheckCapacity(SL* ps)
{
	assert(ps);
	//扩容
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
}

La razón por la que la verificación se encapsula como una función para verificar el espacio aquí es para facilitar su uso posterior al insertar.

Cuando se creó por primera vez esta tabla de secuencia, su capacidad era 0. En este momento, abriremos espacio para elementos 4. Cuando la capacidad esté llena, duplicaremos directamente la capacidad. Cuando pasamos un puntero nulo en la función realloc, la función realloc en este momento es equivalente a una función malloc, por lo que también es posible usar la función realloc directamente aquí.

  4. Inserción del extremo de la tabla de secuencias

//尾插 O(1)
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}

En primer lugar, debemos verificar el tamaño del espacio de la matriz. Si la capacidad no es suficiente, podemos insertarla directamente. Si la capacidad está llena, primero debemos expandir la capacidad y luego insertar. La función de SLCheckCapacity() es comprobar si la capacidad está llena y, si lo está, la capacidad se ampliará inmediatamente.

  

  5. Eliminar al final de la lista de secuencias

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	///暴力检查
	assert(ps->size > 0);
	ps->size--;
}

La eliminación de cola en realidad solo usa size--, pero un problema a tener en cuenta es que cuando size = 0, la tabla de secuencia en sí está vacía, por lo que no se puede reducir más para evitar el acceso fuera de los límites, por lo que se agregan dos afirmaciones aquí Puedes evitar que esto suceda.

  6. Conector de encabezado de secuencia

//头插 O(N)
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	//检查容量够不够
	SLCheckCapacity(ps);

	//挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}

En primer lugar, el enchufe de la cabeza también debe verificar el tamaño de la capacidad para asegurarse de que la capacidad sea suficiente y luego mover los datos almacenados un bit hacia atrás, desocupando la primera posición y finalmente insertar un nuevo elemento.

  7. Eliminar encabezado de secuencia

//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);
	//挪动数据
	int begin = 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	//暴力检查
	ps->size--;
}

La lógica general de la eliminación de la cabeza y la eliminación de la cola es la misma. Primero debemos verificar si el tamaño es 0. En la siguiente operación, solo necesitamos dejar que los datos subsiguientes sobrescriban los datos anteriores y, finalmente, completar el efecto de la eliminación del encabezado.

  8. Insertar en la posición especificada en la tabla de secuencia 

Insertar en cualquier posición es como una versión mejorada del tapón de cabeza y el tapón de cola, excepto que hay un parámetro adicional pos. Si pos está en la posición inicial, es equivalente a un tapón de cabeza. Si pos está al final, es equivalente a un tapón de cola.

//在pos的位置插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos <= ps->size);
	//检查容量够不够
	SLCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}

Suponiendo que el subíndice de la posición de inserción es pos, solo necesitamos mover todos los datos desde la posición pos hasta el final hacia atrás como un todo, luego vaciar la posición de pos y luego insertar un nuevo elemento en la posición de pos , y finalmente tamaño ++.

Nota: afirmar(pos >= 0); afirmar(pos <= ps->tamaño); Estas dos líneas de código son para limitar el elemento insertado para que esté entre 0 y tamaño, no en otros lugares, para garantizar que el elemento sea entre los elementos se almacenan continuamente.

 

  9. Eliminar la posición especificada en la tabla de secuencia 

//在pos的位置删除数据
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos < ps->size);
	//挪动数据覆盖
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

Primero, debe afirmar si el tamaño es 0. Luego, los datos detrás de pos se mueven hacia adelante como un todo, cubriendo los datos en la posición original de pos y, finalmente, size-.

  10. Consulta de tabla de secuencias

int SLFind(SL* ps, SLDataType x, int begin)
{
	assert(ps);

	for (int i = begin; i < ps->size; ++i)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}

La interfaz de esta función es muy simple, simplemente recorra la matriz una vez, devuelva el subíndice del elemento si lo encuentra y devuelva -1 si no lo encuentra.

  11. Destrucción de la tabla de secuencias

//销毁
void SLDestory(SL* ps)
{
	assert(ps);
	//if (ps->a != NULL)
	if (ps->a)
	{
		free(ps->a);
		ps->a = NULL;
		ps->capacity = 0;
		ps->size = 0;
	}
}

Cuando comenzamos, el espacio abierto dinámicamente se aplicó en el área del montón y debemos liberarlo después de usarlo para evitar pérdidas de memoria.

3. Código fuente

  1、SeqList.h

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

//动态的顺序表 - 按需扩空间
#define N  10
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* a;
	int size;//记录存储多少个有效数据
	int capacity;//空间容量大小
}SL;

void SLPrint(SL* ps);//打印
void SLInit(SL* ps);//初始化
void SLDestory(SL* ps);//销毁
void SLCheckCapacity(SL* ps);//检查空间大小

//尾插
void SLPushBack(SL* ps, SLDataType x);
//尾删
void SLPopBack(SL* ps);

//头插
void SLPushFront(SL* ps, SLDataType x);
//头删
void SLPopFront(SL* ps);

//中间的插入
//在pos位置插入数据
void SLInsert(SL* ps, int pos, SLDataType x);
//中间的删除
//删除pos位置的数据
void SLErase(SL* ps, int pos);

//查找
int SLFind(SL* ps, SLDataType x);

  2, SeqList.c

#include "SeqList.h"

//打印
void SLPrint(SL* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}


//初始化
void SLInit(SL* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

//销毁
void SLDestory(SL* ps)
{
	assert(ps);
	//if (ps->a != NULL)
	if (ps->a)
	{
		free(ps->a);
		ps->a = NULL;
		ps->capacity = 0;
		ps->size = 0;
	}
}

void SLCheckCapacity(SL* ps)
{
	assert(ps);
	//扩容
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
}
//尾插 O(1)
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}
//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	//暴力检查
	assert(ps->size > 0);
	ps->size--;
}

//头插 O(N)
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	//检查容量够不够
	SLCheckCapacity(ps);

	//挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}
//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size > 0);
	//挪动数据
	int begin = 1;
	while (begin < ps->size)
	{
    	ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	//暴力检查
	ps->size--;
}

//在pos的位置插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos <= ps->size);
	//检查容量够不够
	SLCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}
//在pos的位置删除数据
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos < ps->size);
	//挪动数据覆盖
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

//查找
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; ++i)
	{
		if (ps->a[i] == x)
		{
            //找到
			return i;
		}
	}
    //没找到
	return -1;
}

  3, prueba.c

#define _CRT_SECURE_NO_WARNINGS 1	
#include"SeqList.h"
void menu()
{
	printf("*******************************\n");
	printf("******  0.退出   1.打印  ******\n");
	printf("******  2.尾插   3.尾删  ******\n");
	printf("******  4.头插   5.头删  ******\n");
	printf("******  6.任意插 7.任意删******\n");
	printf("******  8.在pos位置插入  ******\n");
	printf("******  9.删除pos元素值  ******\n");
	printf("*******************************\n");
}

int main()
{
	int input = 1;
	SL s;
	SLInit(&s);	//创建一个顺序表
	while (input)
	{
		int pos = 0;
		SLDatatype x = 0;
		SLDatatype y = 0;
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 0:
			printf("退出顺序表!\n");
			SLDestroy(&s);
			break;
		case 1:
			SLPrint(&s);
			break;
		case 2:
			printf("请输入一个值:>");
			scanf("%d", &x);
			SLPushBack(&s, x);
			break;
		case 3:
			SLPopBack(&s);
			break;
		case 4:
			printf("请输入一个值:>");
			scanf("%d", &x);
			SLPushFront(&s, x);
			break;
		case 5:
			SLPopFront(&s);
			break;
		case 6:
			printf("请输入下标和目标值:>");
			scanf("%d %d", &pos, &x);
			SLInsert(&s, pos, x);
			break;
		case 7:
			printf("请输入下标:>");
			scanf("%d", &pos);
			SLErase(&s, pos);
			break;
		case 8:
			printf("请输入要插入元素值和目标值:>");
			scanf("%d %d", &y, &x);
			SLInsert(&s, SeqListFind(&s, y), x);
			break;
		case 9:
			printf("请输入要删除元素值:>");
			scanf("%d", &y);
			SLErase(&s, SeqListFind(&s, y));
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	}
	return 0;
}


 Si hay deficiencias en este artículo, puede comentar a continuación y lo corregiré lo antes posible.

  Hierros viejos, recuerden darle like y atentos!!!

Supongo que te gusta

Origin blog.csdn.net/m0_63198468/article/details/128462011
Recomendado
Clasificación