[Estrutura de dados] Tabela de sequência de implementação da linguagem C (superdetalhada)

Índice

conceito e estrutura

Implementação de função de interface

Inicialização da tabela de sequência

Julgamento de capacidade

 Inserir no final da tabela de sequência

 Excluir do final da tabela de sequência

Inserção de cabeçalho de sequência

Excluir cabeçalho de sequência

Pesquisa de tabela de sequência

Inserir na posição especificada na tabela de sequência

Exclua a posição especificada na tabela de sequência

Tabela de sequência de impressão

Tabela de sequência de destruição

Código completo da tabela de sequência


conceito e estrutura

Tabela sequencial é um tipo de tabela linear. É uma estrutura linear que usa uma unidade de armazenamento com um endereço físico contínuo para armazenar elementos de dados em sequência. Geralmente, é usado armazenamento em array . Conclua a adição, exclusão, verificação e modificação de dados no array.

A tabela de sequência é geralmente dividida em:

1. Tabela de sequência estática - usa matriz de comprimento fixo para armazenar elementos.

#define N 100
//顺序表的静态存储
typedef int SLDatatype;
typedef struct SeqList
{
	SLDataType Data[N]; //定长数组
	int size;           //有效数据个数
}SeqList;

Este método de armazenamento tem limitações ao armazenar dados. Quando a quantidade de dados armazenados é muito pequena, o comprimento do array é muito longo, o que causará desperdício de espaço; quando a quantidade de dados armazenados é muito grande, o espaço do array pode não ser suficiente, mas este método de armazenamento não pode ser expandido. Portanto, ao implementar uma tabela de sequência, geralmente usamos uma tabela de sequência dinâmica. Isso pode melhorar nossa utilização do espaço.

2. Tabela de sequência dinâmica - usa matrizes abertas dinamicamente para armazenar elementos.

//顺序表的动态存储
typedef int SLDatatype;
typedef struct SeqList
{
	SLDataType* Data; //定长数组
	int size;         //有效数据个数
	int capacity;     //空间容量的大小
}SeqList;

Implementação de função de interface

Inicialização da tabela de sequência

//初始化链表
void SLInit(SeqList* ps)
{
	assert(ps);   //判空,如果传入的空指针,后面对它进行解引用就会报错
	ps->data = NULL; //将data初始化为空指针
	ps->capacity = ps->size = 0;
}

Agora que a inicialização da tabela de sequências foi concluída, a próxima etapa é adicionar, excluir, verificar e modificar a tabela de sequências.

Antes de implementar a função de adicionar elementos à lista de sequências, primeiro implementamos uma verificação para ver se a lista de sequências está cheia. Se estiver cheio, precisamos expandi-lo.

Julgamento de capacidade

//容量判断
void Check_Capacity(SeqList* ps)
{
	assert(ps);
	if (ps->capacity == ps->size) //判断顺序表中有效数据个数是否已经达到容量大小
	{
		int new_capacity = ps->capacity == 0 ? 4 : (ps->capacity) * 2;
        //如果容量为0的话,此时就是第一次向顺序表中添加元素,capacity就设为4
        //如果容量不为0,此时就是有效数据个数达到容量,就进行扩容,新容量设置为原容量的2倍
		SLDataType* tmp = (SLDataType*)realloc(ps->data, new_capacity * sizeof(SLDataType));
		if (tmp == NULL)  //如果扩容失败,就终止程序。
		{
			perror("ralloc fail");
			exit(-1);
		}
		ps->data = tmp;
		ps->capacity = new_capacity;
	}
}

A função realloc é usada para expansão aqui. Quando inserimos pela primeira vez, o ponteiro ps->data ainda é um ponteiro nulo. Neste momento, também podemos usar realloc. Quando a função realloc é usada, se o ponteiro de entrada é um ponteiro nulo, sua função é a mesma de malloc. 

 Inserir no final da tabela de sequência

//顺序表尾插
void SL_PushBack(SL* ps, SLDataType x)
{
	assert(ps);
	Check_Capacity(ps);
	ps->data[ps->size] = x;
	ps->size++;
}

 Excluir do final da tabela de sequência

//顺序表尾删
void SL_PopBack(SL* ps)
{
	assert(ps);
	assert(ps->size > 0); //如果顺序表中已经没有元素,那么就不用进行删除,所以
                          //这里需要检查顺序表中是否还有元素。
	ps->size--;
}

 Quer se trate de exclusão final ou de cabeçalho, a tabela de sequência deve ser verificada para ver se há algum elemento na tabela.

Inserção de cabeçalho de sequência

//顺序表头插
void SL_PushFront(SL* ps, SLDataType x)
{
	assert(ps);
	Check_Capacity(ps); //检查容量
    //将所有数据向后移动一位
	for (int i = ps->size - 1; i >= 0; i--)
	{
		ps->data[i + 1] = ps->data[i];
	}
	ps->data[0] = x;
	ps->size++;
}

Ao inserir o cabeçote, não precisamos apenas verificar a capacidade, mas também mover os dados um bit para trás antes de inserir, caso contrário, os dados serão perdidos.

Excluir cabeçalho de sequência

//顺序表头删
void SL_PopFront(SL* ps)
{
	assert(ps);
    //如果顺序表中只有一个数据,那么直接将数据个数-1
    //如果对数据进行挪动,会造成越界
	if (ps->size == 1)
	{
		ps->size--;
		return;
	}
    如果数据个数不为1,就将数据中第2个到最后一个都往前移动一位
	for (int i = 1; i < ps->size; i++)
	{
		ps->data[i - 1] = ps->data[i];
	}
	ps->size--;
}

Pesquisa de tabela de sequência

//顺序表查找
int SL_Find(SeqList* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->data[i] == x)
		{
            //找到就返回下标
			return i;
		}
	}
    //找不到就返回-1
	return -1;
}

Inserir na posição especificada na tabela de sequência

//顺序表指定位置插入
void SL_Insert(SeqList* ps, int pos, SLDataType x)
{
	assert(ps);
    //判定pos是否合法
	assert(pos <= ps->size);
	assert(pos >= 0);
	Check_Capacity(ps); //检查容量是否够用
    //将pos位置后的元素全部都向后移动一位
	for (int i = ps->size-1; i >= pos; i--)
	{
		ps->data[i + 1] = ps->data[i];
	}
	ps->data[pos] = x;
	ps->size++;
}

Exclua a posição especificada na tabela de sequência

//顺序表指定位置删除
void SL_Erase(SeqList* ps, int pos)
{
	assert(ps);
    //检查pos位置是否合法
	assert(pos >= 0);
	assert(pos < ps->size);
    //将pos位置后面的元素全都向前移动一位
	for (int i = pos; i < ps->size; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->size--;
}

Com a inserção e exclusão na posição especificada na tabela de sequência, podemos reescrever a inserção e exclusão da cauda e a exclusão do plug da cabeça :

//尾插
void SL_PushBack(SeqList* ps, SLDataType x)
{
	SL_Insert(ps, ps->size, x);
}

//尾删
void SL_PopBack(SeqList* ps)
{
	SL_Erase(ps, ps->size - 1);
}
//头插
void SL_PushFront(SeqList* ps, SLDataType x)
{
	SL_Insert(ps, 0, x);
}
//头删
void SL_PopFront(SeqList* ps)
{
	SL_Erase(ps,0);
}

Tabela de sequência de impressão

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

Tabela de sequência de destruição

//销毁顺序表
void SL_Destroy(SeqList* ps)
{
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->capacity = ps->size = 0;
}

Código completo da tabela de sequência

SeqList.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* data;
	int size;
	int capacity;
}SeqList;

//初始化顺序表
void SLInit(SeqList* ps);

//删除顺序表
void SL_Destroy(SeqList* ps);

//打印顺序表
void SLPrint(SeqList* ps);

//检查容量
void Check_Capacity(SeqList* ps);

//尾插尾删
void SL_PushBack(SeqList* ps,SLDataType x);
void SL_PopBack(SeqList* ps);

//头插头删
void SL_PushFront(SeqList* ps, SLDataType x);
void SL_PopFront(SeqList* ps);

//顺序表查找
int SL_Find(SeqList* ps, SLDataType x);

//顺序表指定位置插入
void SL_Insert(SeqList* ps, int pos, SLDataType x);

//顺序表指定位置删除
void SL_Erase(SeqList* ps, int pos);

SeqList.c

#include "SeqList.h"

void SLInit(SeqList* ps)
{
	assert(ps);  
	ps->data = NULL; 
	ps->capacity = ps->size = 0;
}

void SL_Destroy(SeqList* ps)
{
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->capacity = ps->size = 0;
}

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

void Check_Capacity(SeqList* ps)
{
	assert(ps);
	if (ps->capacity == ps->size) 
	{
		int new_capacity = ps->capacity == 0 ? 4 : (ps->capacity) * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->data, new_capacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("ralloc fail");
			exit(-1);
		}
		ps->data = tmp;
		ps->capacity = new_capacity;
	}
}

void SL_PushBack(SeqList* ps, SLDataType x)
{
	//assert(ps);
	//Check_Capacity(ps);
	//ps->a[ps->size] = x;
	//ps->size++;
	SL_Insert(ps, ps->size, x);
}

void SL_PopBack(SeqList* ps)
{
	//assert(ps);
	//assert(ps->size > 0);
	//ps->size--;
	SL_Erase(ps, ps->size - 1);
}

void SL_PushFront(SeqList* ps, SLDataType x)
{
	//assert(ps);
	//Check_Capacity(ps);
	//for (int i = ps->size - 1; i >= 0; i--)
	//{
	//	ps->a[i + 1] = ps->a[i];
	//}
	//ps->a[0] = x;
	//ps->size++;
	SL_Insert(ps, 0, x);
}

void SL_PopFront(SeqList* ps)
{
	//assert(ps);
	//if (ps->size == 1)
	//{
	//	ps->size--;
	//	return;
	//}
	//for (int i = 1; i < ps->size; i++)
	//{
	//	ps->data[i - 1] = ps->data[i];
	//}
	//ps->size--;
	SL_Erase(ps,0);
}

int SL_Find(SeqList* ps, SLDataType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->data[i] == x)
		{
			return i;
		}
	}
	return -1;
}

void SL_Insert(SeqList* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos <= ps->size);
	assert(pos >= 0);
	Check_Capacity(ps);
	for (int i = ps->size-1; i >= pos; i--)
	{
		ps->data[i + 1] = ps->data[i];
	}
	ps->data[pos] = x;
	ps->size++;
}

void SL_Erase(SeqList* ps, int pos)
{
	assert(ps);
	assert(pos >= 0);
	assert(pos < ps->size);
	for (int i = pos; i < ps->size; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->size--;
}

Acima está todo o conteúdo relacionado à tabela de sequência, espero que possa ajudar a todos.

Acho que você gosta

Origin blog.csdn.net/m0_74459723/article/details/128512663
Recomendado
Clasificación