[Estructura de datos] Lo lleva a descubrir fácilmente la tabla de secuencias (con el código fuente incluido)

inserte la descripción de la imagen aquí

Página de inicio personal de Junxi_

Sé diligente y anima los años a no esperar a nadie.

Desarrollo de juegos C/C++


Hola, Mina-san, aquí Junxi_, ¡y hoy comenzamos oficialmente a abrir un nuevo pozo! En el próximo mes, te introduciré gradualmente al conocimiento de las estructuras de datos elementales. Si te estás especializando en informática, la importancia de las estructuras de datos es evidente, incluso en tus futuras entrevistas de trabajo. Uno de los contenidos que A los entrevistadores les gusta más investigar, si desea tener una comprensión sistemática y profunda de esta parte del contenido, ¡no se pierda el contenido de esta columna! ! ¡Haré todo lo posible para que comiences con palabras fáciles de entender!
Bueno, sin más preámbulos, ¡comencemos el estudio de hoy!

prefacio

pd: El punto más incomprensible en la tabla de secuencias debería ser el uso de malloc y realloc. Este es el conocimiento sobre la gestión de memoria dinámica en lenguaje C. Nuestro objetivo principal es introducir la tabla de secuencias, por lo que no haremos una narración. Si Si está interesado, ¡también actualizaré el blog y publicaré el enlace aquí!

1. Mesa lineal

Sabemos que la tabla de secuencia es la tabla lineal más básica, entonces, ¿qué es una tabla lineal?

1. El concepto de mesa lineal

  • Una lista lineal es una secuencia finita de n elementos de datos con las mismas propiedades. La tabla lineal es una estructura de datos ampliamente utilizada en la práctica, tabla lineal común: lista secuencial, 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 la tabla lineal se almacena físicamente, generalmente se almacena en forma de matriz y estructura de cadena.
    inserte la descripción de la imagen aquí

2. Tabla de secuencias

2.1 Concepto y estructura

  • 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.
  • Nota: Lo que necesitamos saber aquí es que los datos almacenados en la tabla secuencial son continuos y se almacenan secuencialmente en la memoria. ¡Esta es la mayor diferencia con la lista enlazada!

2.2 Clasificación de la tabla de secuencia

  • Generalmente hay dos formas de
  • 1. Tabla de secuencia estática: use una matriz de longitud fija para almacenar elementos.
// 静态顺序表
#define N 1000
typedef int SLDataType;

struct SeqList
{
    
    
	SLDataType a[N];
	int size;
};
  • La tabla de secuencia estática solo es adecuada para escenarios en los que sabe cuántos datos deben almacenarse. La matriz de longitud fija de la tabla de secuencia estática hace que N sea fijo, y el espacio se desperdicia si se abre demasiado, y no es suficiente si se abre demasiado poco. Por lo tanto, en realidad, se usa básicamente el segundo tipo de tabla de secuencia, la tabla de secuencia dinámica, y el tamaño del espacio se asigna dinámicamente de acuerdo con las necesidades.
  • 2. Tabla de secuencia dinámica
// 动态顺序表
typedef int SLDataType;//重命名数据类型,方便以后直接修改

typedef struct SeqList
{
    
    
	SLDataType* a;//指向动态开辟的数组
	int size;        // 存储有效数据个数
	int capacity;    // 容量空间大小
}SL;
  • 顾名思义,动态顺序表使用动态开辟的数组储存,这样更方便我们实时根据数据的多少调整数组的大小。。
  • Aquí hay algunos puntos importantes para recordar el código anterior:
  • 1. Hemos usado dos typedefs en el código anterior, pero tienen diferentes usos
    • El primer typedef es en realidad para nuestra conveniencia, porque no sabemos qué tipo de datos se usa para almacenar nuestra tabla de secuencias, por lo que definimos un SLDataType aquí y lo usamos uniformemente en el código siguiente. En su lugar, de esta manera, si queremos cambiar el tipo de datos almacenados en el futuro, solo necesitamos cambiar aquí, por ejemplo, queremos almacenar datos de tipo doble ahora
typedef double SLDataType;
    • El segundo typedef es para cambiar el nombre de esta estructura para facilitar nuestro uso posterior, y la siguiente estructura puede escribir directamente 'SL'.

A continuación, implementemos las diversas funciones y métodos de uso de la tabla de secuencia dinámica.


2.3 Realización de la tabla de secuencia dinámica

Inicialización de la tabla de secuencia

  • 我们确定了顺序表内的基本内容,我们得把顺序表先初始化一下,不然连空间都还没开辟咋使用呢?
//初始化顺序表
void SLInit(SL* ps)
{
    
    
    ps->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);//申请四个字节的空间,如果不够再进行增容
    if (ps->a == NULL)
    {
    
    
        perror("malloc failed");
        exit (-1);
    }
    ps->size = 0;
    ps->capacity = 4;
}
  • Hemos solicitado cuatro bytes de espacio para nuestra tabla de secuencias a través de malloc y aún no hemos completado los datos en este momento, por lo que el tamaño se inicializa en 0 y el espacio de capacidad es 4.
  • Pero acabamos de solicitar espacio, y no sabemos si tiene éxito, así que juzgamos si nuestra operación de abrir memoria es exitosa distinguiendo si la matriz dinámica es NULL e informando un error a través de perror.

Expansión de la tabla de secuencia

  • 我们初始化了一个顺序表,但是我们并不知道我们申请的空间是否够用,如果不够用,我们就得扩容一下。因此我们这里的逻辑应该是先判断容量是否够用,够用就不用做多余的操作,如果不够用,就申请扩容
//检查空间,如果顺序表满了,就进行增容操作
void SLCheckCapacity(SL* ps)
{
    
    
    assert(ps);//断言防止传入ps为空
    //判断一下是否空间满了,如果满了就把容量增加到原来的2倍
    if (ps->size == ps->capacity)//有效数据是否占满所有空间
    {
    
    
        SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * (sizeof(SLDataType)));//利用realloc扩容
        if (tmp == NULL)
        {
    
    
            perror("realloc failed");
            exit(-1);
        }
        ps->a = tmp;
        ps->capacity *= 2;
    }
}
  • Aquí usamos realloc para expandir el espacio al doble del tamaño original. Cuando juzguemos que la expansión es exitosa a través de perror, asignaremos la expansión a nuestro arreglo dinámico. Dado que la expansión es el doble del tamaño original, el espacio de capacidad aquí también será el original 2 veces.

Destrucción de la tabla de secuencias

  • Cuando terminemos de usar la tabla de secuencias, ya que usamos malloc para abrir la memoria, debemos destruirla y liberarla
void SLDestroy(SL* ps)
{
    
    
    free(ps->a);//释放malloc申请的空间并且将a指向NULL
    ps->a = NULL;
    ps->capacity = ps->size = 0;

}
  • 在销毁并释放内存的同时,我们也需要把size和capacity初始化一下。

Impresión de tabla de secuencia

  • Cuando insertamos o borramos datos, necesitamos imprimir la tabla de secuencia para ver si nuestra operación es exitosa
void SLPrint(SL* ps)
{
    
    
    int i =0;
    for (i = 0; i < ps->size; i++)
        printf("%d ", ps->a[i]);//把有效数据通过循环都打印一下
    printf("\n");
}
  • Si los platos anteriores son todos aperitivos, entraremos en la cena de hoy, que es también la parte más difícil de la tabla de secuencias, que es lo que llamamos adiciones, eliminaciones, comprobaciones y cambios.

Inserción de cola y eliminación de tabla de secuencia

  • ¿Qué es la inserción de cola y la eliminación de cola?
  • **所谓尾插就是从顺序表的末尾插入数据,而尾删就是把最后一个数据给删除**
//顺序表尾插
void SLPushBack(SL* ps, SLDataType x)
{
    
    
    assert(ps);
    SLCheckCapacity(ps);//先判断以下顺序表是否已满,未满才能插入数据
    ps->a[ps->size] = x;//把数组a中size位置的数据赋值为x,size位置即最后一位
    ps->size++;//插入数据成功,有效数据+1
}
  • Entre ellos, al eliminar la cola, debemos verificar si está fuera de los límites. Por ejemplo, si solo tiene dos datos y elimina la cola 10 veces, entonces sus datos válidos se volverán negativos en este momento. ¿Ha cruzado? los límites en este momento?
  • Hay dos formas de verificar si se cruza la línea. Me gustaría llamarlo verificación suave y verificación de fuerza bruta. ¿Qué está pasando aquí?
//顺序表尾删
void SLPopBack(SL* ps)
{
    
    

    assert(ps);
    温柔的检查
    //if (ps->size == 0)
    //    return;
    //暴力检查
    assert(ps->size > 0);
    ps->a[ps->size - 1] = 0;//把最后一个数据抹掉
    ps->size--;//有效数据-1

}
  • ¿Qué es la inspección suave?
  • Cuando se ha eliminado nuestro tamaño (tamaño == 0), significa que se han eliminado todos los datos válidos y luego podemos regresar directamente. En este momento, el programa no bajará y conducirá a cruzar el límite, ni informará un error.
  • Y la ley de fuerza bruta es como tu padre estricto
  • Afirmamos directamente a través de la afirmación, si descubre que ha cruzado el límite, sacará directamente a los siete lobos (informará un error) y le advertirá dónde está equivocado, como se muestra a continuación.
    inserte la descripción de la imagen aquí
    . . . Fuera de lugar, de la siguiente manera:
    inserte la descripción de la imagen aquí

Inserción y eliminación de encabezados de la tabla de secuencias

  • 与尾插和尾删类似,顺序表的头插与头删就是在开头进行插入与删除数据操作
/顺序表的头插
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 el proceso de inserción de la cabeza, debemos prestar atención a eso, para insertar un dato en la cabeza, debemos mover todos los datos en la tabla de secuencias un bit hacia atrás para dar paso a la inserción de la cabeza.
//顺序表的头删
void SLPopFront(SL* ps)
{
    
    
    assert(ps);
    int begin = 0;
    while (begin < ps->size-1)
    {
    
    
        ps->a[begin] = ps->a[begin + 1];
        begin++;
    }
    ps->size--;
}
  • En la eliminación de encabezados, similar a la inserción de encabezados, necesitamos mover todos los datos un bit hacia adelante para compensar la vacante de la eliminación de encabezados y, finalmente, reducir los datos válidos en un bit.

Eliminación e inserción en cualquier posición de la tabla de secuencias

//在顺序表中pos位置插入
void SLInsert(SL* ps, int pos, SLDataType x)
{
    
    
    assert(ps);
    SLCheckCapacity(ps);//检查容量空间大小
    assert(pos >= 0 && pos <= ps->size);//判断pos的合法化,避免插入到非法坐标中
    int end = ps->size - 1;
    while (end >= pos)//把pos位置后的数据都朝后挪动一位,给插入的数据腾位置
    {
    
    
        ps->a[end + 1] = ps->a[end];
        end--;
    }
    ps->a[pos] = x;//插入数据
    ps->size++;//有效数字+1

}
  • 这里与头插类似,只不过我们需要挪动的数据变成了pos位置后的数据,它们都需要朝后挪动一位
//在顺序表中删除pos位置的值
void SLErase(SL* ps, int pos)
{
    
    
    assert(ps);
    assert(pos >= 0 && pos <= ps->size);
    int begin = pos;
    while (begin < ps->size-1)
    {
    
    
        ps->a[begin] = ps->a[begin + 1];//pos后的数据都朝前挪动一位
        begin++;
    }
    ps->size--;//有效数据-1
}
  • 与头删类似,pos后面的数据都要朝前挪动一位来填补删除pos位置上数据的空缺

Buscar y modificar datos en la tabla de secuencia

  • Búsqueda de datos en la tabla de secuencia
//查找顺序表中是否有某个数,如果有就返回该数的下标

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;
}
  • Encuentre si hay ciertos datos atravesando la forma de la matriz, devuelva la ubicación de los datos si se encuentran y devuelva -1 si no se encuentran.
  • Modificaciones en la tabla de secuencia
  • Para modificar, necesitamos saber qué datos de ubicación modificar y cuánto queremos modificar los datos en esa ubicación
void SLModify(SL* ps, int pos, SLDataType x)
{
    
    
    assert(ps);

    assert(pos >= 0 && pos < ps->size);//判断要修改数据的坐标是否合法

    ps->a[pos] = x;//修改数据
}


2.4 Pruebe nuestra tabla de secuencia dinámica

  • Bueno, las funciones básicas de nuestra tabla de secuencia se implementaron a través del código, seleccionemos algunas funciones importantes y pruébelas ahora.
int main()
{
    
    
    SL s1;
    SLInit(&s1);
    SLPushBack(&s1, 1);
    SLInsert(&s1, 1, 50);
    SLPushFront(&s1, 20);
    SLPrint(&s1);
  
    int ret=SLFind(&s1, 50);
    if(ret!=-1)
    printf("找到了,下标是%d\n", ret);
    SLErase(&s1, 0);
    SLPopBack(&s1);
   
    SLPrint(&s1);
    SLModify(&s1, 0, 666);
    SLPrint(&s1);

    
    return 0;
}

inserte la descripción de la imagen aquí

  • Compare cuidadosamente las funciones que queremos lograr y descubra que no hay problema con Queshi

2.5 Ventajas y desventajas de las tablas de secuencia

  • Problemas existentes:
  • 1. Inserción y eliminación en el medio/cabeza, la complejidad del tiempo es O(N)
  • 2. Para aumentar la capacidad, debe solicitar un nuevo espacio, copiar datos y liberar espacio antiguo. Habrá mucho consumo. (especialmente expansión remota)
  • 3. El aumento de la capacidad es generalmente un aumento de 2 veces, y seguramente habrá una cierta cantidad de desperdicio de espacio.
    Por ejemplo, la capacidad actual es 100 y la capacidad aumenta a 200 cuando está llena. Continuamos insertando 5 datos y no se insertarán datos más tarde, por lo que se desperdiciarán 95 espacios de datos.
  • ventaja
  • 1. La eliminación y la inserción de la cola son lo suficientemente rápidas
  • 2. El acceso aleatorio y la modificación se pueden realizar a través de subíndices (esto es muy importante)

Resumir

  • El contenido de hoy está aquí, y lo llevaremos a realizar la escritura de la tabla de secuencia en detalle. Por razones de espacio, hablaremos sobre los puntos propensos a errores y varios detalles en la compilación de la tabla de secuencias en el próximo artículo. Al mismo tiempo, también hablaremos sobre algunas preguntas de entrevista relacionadas para profundizar la comprensión de estos por parte de todos. puntos propensos a errores.
  • pd: De hecho, es demasiado tarde para quedarse despierto hasta tarde para escribir un blog, y el blogger no puede soportarlo más. Por el arduo trabajo del blogger, ¿realmente no quieres dejar tus tres empresas? ! !
  • Bueno, si tiene alguna pregunta, por favor pregúnteme en el área de comentarios o mensaje privado, ¡hasta la próxima!

No es fácil crear un nuevo blogger. Si cree que el contenido del artículo es útil para usted, puede hacer clic en este nuevo blogger antes de irse. ¡Tu apoyo es mi motivación para actualizar! ! !

**(¡Ke Li te pide que apoyes al bloguero tres veces seguidas! Haz clic en el comentario a continuación para darle me gusta y recolectar para ayudar a Ke Li)**

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/syf666250/article/details/131950016
Recomendado
Clasificación