数据结构基础-线性表

89 阅读4分钟

知识点预习

指针的概念

#include <stdio.h>
int main()
{
    int a = 5, b = 9;
    int *p = &a; // (int *) p=&a 只有初始化时需要加*,赋值不需要
    printf("a = %d\n", a);
    printf("p = %d\n", *p);
    p = &b; // 取b的地址赋值给p,直接赋值
    printf("b = %d\n", b);
    printf("p = %d\n", *p);

    int num[105] = {9, 8, 7}; // num <=>&num[0]
    int *q = num;
    q[1] = 100;
    printf("%d %d %d\n", num[0], num[1], num[2]);
    printf("num size=%lu,a size=%lu\n", sizeof(num), sizeof(a));        // sizeof 长度
    printf("a->%p\nb->%p\np->%p\nnum->%p\nq->%p\n", &a, &b, p, num, q); // &a 取a地址
    return 0;
}
  • 输出
$ gcc point.c
$ ./a.out
a = 5
p = 5
b = 9
p = 9
9 100 7
num size=420,a size=4
a->0x7ffeeed7a898
b->0x7ffeeed7a894
p->0x7ffeeed7a894
num->0x7ffeeed7a8a0
q->0x7ffeeed7a8a0

结构体

#include <stdio.h>
typedef struct node // 类型structnode 
{
    int x, y;
} node; // 启别名 typedef...{...}node

int main()
{
    node a;
    a.x = 5; //普通变量".""
    a.y = 20;
    printf("a.x = %d,a.y = %d\n", a.x, a.y);
    node *p = &a; // 指针使用"->"
    p->x = 9;
    p->y = 100;
    printf("a.x = %d,a.y = %d\n", a.x, p->y);
    return 0;
}

输出

$ gcc typestruct.c
$ ./a.out         
a.x = 5,a.y = 20
a.x = 9,a.y = 100

动态类型分配

动态内存管理

malloc

定义于头文件 <stdlib.h>

void* malloc( size_t size );

分配 size 字节的未初始化内存。

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

int main()
{
    int *num = (int *)malloc(100000 * sizeof(int));
    // 定义一个int型的指针num
    // (int *) 强制类型转换
    // 100000 * sizeof(int) 申请了一个100000个int空间大小的空间
    num[0] = 123;
    num[99999] = 12345;

    printf("%d %d %d\n", num[0], num[99999], num[12000]);
    
    free(num); // 释放申请空间,虽然可以访问,但是是一个危险操作
    num = NULL; // 设置值
    return 0;
}

输出

$ gcc malloc.c
$ ./a.out     
123 12345 0

线性表

线性表的顺序存储又叫做顺序表,它是由一组地址连续的存储单元依次存储线性表中的数据元素,从而使得逻辑上相邻的两个元素,在物理位置上也相邻。(大家可以先简单的理解成数组)

插入新值

image.png

删除值

image.png

/**
 * @file lintable.c
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2022-04-15
 *
 * @copyright Copyright (c) 2022
 *  顺序表
 */
#include <stdio.h>
#include <stdlib.h> // 为了动态内存分配
typedef struct vector
{
    int *data;
    int size, cap; // size 已经存储的变量个数 cap 容量上线
} vector;
// 结构初始化
vector *init(int cnt)
{
    vector *p = (vector *)malloc(sizeof(vector)); // 申请顺序表空间
    p->data = (int *)malloc(sizeof(int) * cnt);   // 申请顺序表存储数据空间
    p->size = 0;
    p->cap = cnt;
    return p;
}
// 销毁
void delete_vector(vector *p)
{
    // 先销毁
    free(p->data);
    free(p);
}

void show_vector(vector *v)
{
    printf("----size-%d,cap-%d-----\n", v->size, v->cap);
    for (int i = 0; i < v->size; i++)
    {
        printf("%d ", v->data[i]);
    }
    printf("\n-----------\n");
}

// 在下标ind 插入val。 1 失败,0 成功
int insert_ele(vector *v, int ind, int val)
{
    if (ind > v->size)
    {
        return 1; // 插入失败,无法跳跃插入
    }
    if (v->size == v->cap)
    {

        v->cap *= 2;                                             // 扩容为原来的2倍
        v->data = (int *)realloc(v->data, sizeof(int) * v->cap); // 新的空间指针赋值老数据
    }
    for (int i = v->size; i > ind; i--)
    {
        v->data[i] = v->data[i - 1]; // 元素依次后移,空出插入元素位置
    }
    v->data[ind] = val; // 插入元素
    v->size++;          // 插入数量+1
    return 0;
}
// 删除
int delete_ele(vector *v, int ind)
{
    if (ind < 0) // 下标不合法
    {
        return 1;
    }
    if (v->size <= ind) // 删除元素不存在
    {
        return 1;
    }
    for (int i = ind; i < v->size - 1; i++)
    {
        v->data[i] = v->data[i + 1]; // 将后面的元素向前移动
    }
    v->size--; // 元素数量-1
    return 0;
}
int main()
{
    int n, cnt;
    scanf("%d%d", &n, &cnt);
    vector *v = init(cnt);
    for (int i = 0; i < n; i++)
    {
        int a, b;
        scanf("%d", &a);
        if (a == 0)
        {
            scanf("%d%d", &a, &b);
            insert_ele(v, a, b);
        }
        else if (a == 1)
        {
            scanf("%d", &a);
            delete_ele(v, a);
        }
        show_vector(v);
    }
    delete_vector(v);
    v = NULL;
    return 0;
}

链表

链表的插入

image.png

链表的删除

image.png

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

typedef struct node
{
    int data;
    struct node *next;
} node;

typedef struct list
{
    int size;
    struct node *head;
} list;
// 初始化新节点
node *get_new_node(int val)
{
    node *p = (node *)malloc(sizeof(node));
    p->data = val;
    p->next = NULL;
    return p;
}
// 初始化链表
list *init()
{
    list *p = (list *)malloc(sizeof(list));
    p->head = get_new_node(0);
    p->size = 0;
    return p;
}
// 删除链表
void delete_list(list *p)
{
    node *q = p->head;
    // 先释放节点,在释放链表
    for (int i = 0; i <= p->size; i++) // <=删除头节点
    {
        node *t = q->next;
        free(q);
        q = t;
    }
    free(p);
}
// 查看链表
void show_list(list *l)
{
    printf("----size=%d----\n", l->size);
    for (node *p = l->head->next; p != NULL; p = p->next)
    {
        printf("%d->", p->data);
    }
    printf("NULL\n--------\n");
}
// ind 位置插入val节点
int insert_ele(list *l, int ind, int val)
{
    if (ind > l->size) //位置不存在
    {
        return 1;
    }
    // 找到之前的元素
    node *p = l->head;
    for (int i = 0; i < ind; i++) // 从前向后找到ind的前一个节点
    {
        p = p->next;
    }

    node *q = get_new_node(val); // 获取新节点
    q->next = p->next;           // 调整指针
    p->next = q;
    l->size++;
    return 0;
}
// 删除节点
int delete_ele(list *l, int ind)
{
    if (l->size <= ind) // 节点不存在
    {
        return 1;
    }
    // 找到之前的元素
    node *p = l->head;
    for (int i = 0; i < ind; i++) // 从前向后找到ind的前一个节点
    {
        p = p->next;
    }
    node *q = p->next;
    p->next = q->next;
    free(q);
    l->size--;
    return 0;
}
int main()
{
    int n; // 操作次数
    scanf("%d", &n);
    list *l = init();
    for (int i = 0; i < n; i++)
    {
        int a, b;
        scanf("%d", &a);
        if (a == 0) // a = 0 新增
        {
            scanf("%d%d", &a, &b);
            insert_ele(l, a, b);
        }
        else if (a == 1) // a = 1 删除
        {
            scanf("%d", &a);
            delete_ele(l, a);
        }
        show_list(l);
    }
    delete_list(l);
    l = NULL;
    return 0;
}
  • 新增代码对比

image.png

  • 删除代码对比 image.png