[Estructura de datos] El lenguaje C implementa operaciones de tablas lineales

Tabla lineal: una secuencia finita de cero o más elementos de datos

 

Enfatice algunos puntos:

Primero es una secuencia. Es decir, hay un orden entre los elementos, si hay varios elementos, el primer elemento no tiene antecesor, el último elemento no tiene sucesor y los demás tienen un antecesor y un sucesor.

En segundo lugar, el énfasis de la tabla lineal es limitado.

La tabla lineal tiene dos estructuras físicas, la primera es una estructura de almacenamiento secuencial y la otra es una estructura de almacenamiento encadenada.


La estructura de almacenamiento secuencial de la tabla lineal se refiere al almacenamiento de los elementos de datos de la tabla lineal en secuencia con un segmento de unidades de almacenamiento con direcciones consecutivas. La estructura de almacenamiento secuencial se implementa con arreglos unidimensionales en lenguaje C.

Ventajas y desventajas de la estructura de almacenamiento secuencial de tabla lineal

Ventajas : puede leer rápidamente elementos en cualquier posición de la tabla

No es necesario agregar espacio de almacenamiento adicional para representar las relaciones lógicas entre los elementos de la tabla

Desventaja : las operaciones de inserción y eliminación requieren mover muchos elementos

Cuando la longitud de la mesa lineal varía mucho, es difícil determinar la capacidad del espacio de almacenamiento

Espacio de almacenamiento "roto"

De hecho, la mayor desventaja de la estructura de almacenamiento secuencial es que es necesario mover una gran cantidad de elementos durante la inserción y eliminación, lo que obviamente lleva tiempo. Así que marcamos el comienzo de la segunda estructura de almacenamiento de la mesa lineal: estructura de almacenamiento en cadena

La característica de la estructura de almacenamiento en cadena es utilizar un grupo de unidades de almacenamiento arbitrarias para almacenar los elementos de datos de la tabla lineal, y este grupo de unidades de almacenamiento puede ser continuo o discontinuo.

En la estructura de almacenamiento secuencial, cada elemento de datos necesita almacenar la información del elemento de datos. Ahora, en la estructura de la cadena, además de almacenar la información del elemento de datos, también se almacena la dirección de su elemento sucesor.

 El campo que almacena la información del elemento de datos se denomina campo de datos, y el campo que almacena la posición del sucesor inmediato se denomina campo de puntero.

 

 Hablemos de las ventajas de las listas enlazadas

puntero de estructura

El almacenamiento se puede asignar dinámicamente

Todos los nodos están distribuidos discretamente, vinculados solo por punteros

Listo para trabajar

archivo principal

#include "stdio.h"    

#include "stdlib.h"  
#include "math.h"  
#include "time.h"

 Definición de macros y uso de typedef

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20 /* 存储空间初始分配量 */

typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */

Estructura y su definición

typedef struct Node
{
    ElemType data;
    struct Node* next;
}Node;
typedef struct Node* LinkList; /* 定义LinkList */

función malloc

Aquí hay una breve introducción al uso de la función malloc

puntero en sí = (tipo de puntero *) malloc(tamaño(tipo de puntero))

Nota:

1. malloc devuelve un puntero sin tipo, que debe convertirse al tipo deseado al usarlo

2. Después de abrir el espacio, asegúrese de liberarlo, de lo contrario, se producirán pérdidas de memoria.

3. La función free(p) libera el espacio de almacenamiento de la variable a la que apunta p y elimina por completo una variable

 Otras Consideraciones

Cuando pasa un parámetro a una función, si el parámetro se cambia o no dentro de la función determina qué forma de parámetro se usa

Si necesita cambiarse, debe pasar un puntero a este parámetro

Si no es necesario cambiarlo, este parámetro se puede pasar directamente.

 Siempre preste atención a este punto, no siempre encuentre funciones que soliciten punteros por un tiempo y se confundan cuando no quieran punteros por un tiempo y no entiendan.

Hablemos de la operación básica de la lista enlazada simple

Inicialización de una lista enlazada individualmente (el campo del puntero del nodo principal está vacío)

/* 初始化链式线性表 */
Status InitList(LinkList* L)
{
    *L = (LinkList)malloc(sizeof(Node)); /* 产生头结点,并使L指向此头结点 */
    if (!(*L)) /* 存储分配失败 */
        return ERROR;
    (*L)->next = NULL; /* 指针域为空 */

    return OK;
}

Determine si la lista vinculada está vacía (en realidad, se basa en si el nodo principal está vacío. Devuelve 1 para vacío, devuelve 0 para no vacío)

/* 初始条件:链式线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(LinkList L)
{
    if (L->next)
        return FALSE;
    else
        return TRUE;

Borrar la lista enlazada

/* 初始条件:链式线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(LinkList *L)
{ 
	LinkList p,q;
	p=(*L)->next;           /*  p指向第一个结点 */
	while(p)                /*  没到表尾 */
	{
		q=p->next;
		free(p);
		p=q;
	}
	(*L)->next=NULL;        /* 头结点指针域为空 */
	return OK;
}

Encuentra la longitud de la lista enlazada

/* 初始条件:链式线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(LinkList L)
{
    int i = 0;
    LinkList p = L->next; /* p指向第一个结点 */
    while (p)
    {
        i++;
        p = p->next;
    }
    return i;
}

valor

/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
Status GetElem(LinkList L,int i,ElemType *e)
{
	int j;
	LinkList p;		/* 声明一结点p */
	p = L->next;		/* 让p指向链表L的第一个结点 */
	j = 1;		/*  j为计数器 */
	while (p && j<i)  /* p不为空或者计数器j还没有等于i时,循环继续 */
	{   
		p = p->next;  /* 让p指向下一个结点 */
		++j;
	}
	if ( !p || j>i ) 
		return ERROR;  /*  第i个元素不存在 */
	*e = p->data;   /*  取第i个元素的数据 */
	return OK;
}

Buscar por valor

/* 初始条件:链式线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int LocateElem(LinkList L,ElemType e)
{
    int i=0;
    LinkList p=L->next;
    while(p)
    {
        i++;
        if(p->data==e) /* 找到这样的数据元素 */
                return i;
        p=p->next;
    }

    return 0;
}

insertar


/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList *L,int i,ElemType e)
{ 
	int j;
	LinkList p,s;
	p = *L;   
	j = 1;
	while (p && j < i)     /* 寻找第i个结点 */
	{
		p = p->next;
		++j;
	} 
	if (!p || j > i) 
		return ERROR;   /* 第i个元素不存在 */
	s = (LinkList)malloc(sizeof(Node));  /*  生成新结点(C语言标准函数) */
	s->data = e;  
	s->next = p->next;      /* 将p的后继结点赋值给s的后继  */
	p->next = s;          /* 将s赋值给p的后继 */
	return OK;
}

Eliminar


/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList *L,int i,ElemType *e) 
{ 
	int j;
	LinkList p,q;
	p = *L;
	j = 1;
	while (p->next && j < i)	/* 遍历寻找第i个元素 */
	{
        p = p->next;
        ++j;
	}
	if (!(p->next) || j > i) 
	    return ERROR;           /* 第i个元素不存在 */
	q = p->next;
	p->next = q->next;			/* 将q的后继赋值给p的后继 */
	*e = q->data;               /* 将q结点中的数据给e */
	free(q);                    /* 让系统回收此结点,释放内存 */
	return OK;
}

El establecimiento de una lista enlazada simple - método de inserción de encabezado

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateListHead(LinkList* L, int n)
{
    LinkList p;
    int i;
    srand(time(0));                         /* 初始化随机数种子 */
    *L = (LinkList)malloc(sizeof(Node));
    (*L)->next = NULL;                      /*  先建立一个带头结点的单链表 */
    for (i = 0; i < n; i++)
    {
        p = (LinkList)malloc(sizeof(Node)); /*  生成新结点 */
        p->data = rand() % 100 + 1;             /*  随机生成100以内的数字 */
        p->next = (*L)->next;
        (*L)->next = p;						/*  插入到表头 */
    }
}

El establecimiento de una lista enlazada simple - método de inserción de cola

/*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateListTail(LinkList* L, int n)
{
    LinkList p, r;
    int i;
    srand(time(0));                      /* 初始化随机数种子 */
    *L = (LinkList)malloc(sizeof(Node)); /* L为整个线性表 */
    r = *L;                                /* r为指向尾部的结点 */
    for (i = 0; i < n; i++)
    {
        p = (Node*)malloc(sizeof(Node)); /*  生成新结点 */
        p->data = rand() % 100 + 1;           /*  随机生成100以内的数字 */
        r->next = p;                        /* 将表尾终端结点的指针指向新结点 */
        r = p;                            /* 将当前的新结点定义为表尾终端结点 */
    }
    r->next = NULL;                       /* 表示当前链表结束 */
}

Nota: con respecto a los datos de p->data, también puede cambiarlos a entrada manual en lugar de generarlos aleatoriamente

Lo importante es entender la idea del algoritmo del método de inserción de la cabeza o el método de inserción de la cola.

 producción

/* 初始条件:链式线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status ListTraverse(LinkList L)
{
    LinkList p = L->next;
    while (p)
    {
        visit(p->data);
        p = p->next;
    }
    printf("\n");
    return OK;
}
Status visit(ElemType c)
{
    printf("%d ", c);
    return OK;
}

función principal

int main()
{
    LinkList L;
    ElemType e;
    Status i;
    int j, k;
    i = InitList(&L);
    printf("初始化L后:ListLength(L)=%d\n", ListLength(L));
    for (j = 1; j <= 5; j++)
        i = ListInsert(&L, 1, j);
    printf("在L的表头依次插入1~5后:L.data=");
    ListTraverse(L);

    printf("ListLength(L)=%d \n", ListLength(L));
    i = ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n", i);

    i = ClearList(&L);
    printf("清空L后:ListLength(L)=%d\n", ListLength(L));
    i = ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n", i);

    for (j = 1; j <= 10; j++)
        ListInsert(&L, j, j);
    printf("在L的表尾依次插入1~10后:L.data=");
    ListTraverse(L);

    printf("ListLength(L)=%d \n", ListLength(L));

    ListInsert(&L, 1, 0);
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L);
    printf("ListLength(L)=%d \n", ListLength(L));

    GetElem(L, 5, &e);
    printf("第5个元素的值为:%d\n", e);
    for (j = 3; j <= 4; j++)
    {
        k = LocateElem(L, j);
        if (k)
            printf("第%d个元素的值为%d\n", k, j);
        else
            printf("没有值为%d的元素\n", j);
    }


    k = ListLength(L); /* k为表长 */
    for (j = k + 1; j >= k; j--)
    {
        i = ListDelete(&L, j, &e); /* 删除第j个数据 */
        if (i == ERROR)
            printf("删除第%d个数据失败\n", j);
        else
            printf("删除第%d个的元素值为:%d\n", j, e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L);

    j = 5;
    ListDelete(&L, j, &e); /* 删除第5个数据 */
    printf("删除第%d个的元素值为:%d\n", j, e);

    printf("依次输出L的元素:");
    ListTraverse(L);

    i = ClearList(&L);
    printf("\n清空L后:ListLength(L)=%d\n", ListLength(L));
    CreateListHead(&L, 20);
    printf("整体创建L的元素(头插法):");
    ListTraverse(L);

    i = ClearList(&L);
    printf("\n删除L后:ListLength(L)=%d\n", ListLength(L));
    CreateListTail(&L, 20);
    printf("整体创建L的元素(尾插法):");
    ListTraverse(L);


    return 0;
}

La originalidad no es fácil, por favor dale a me gusta, este blog termina aquí.

Supongo que te gusta

Origin blog.csdn.net/weixin_60478154/article/details/123054115
Recomendado
Clasificación