002 数据结构_顺序表的实现过程——“C”

引入

什么是顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:

  1. 静态顺序表:使用定长数组存储元素。
  2. 动态顺序表:使用动态开辟的数组存储。

什么是malloc与realloc内存函数

1、
void *malloc( size_t size );
void *返回类型
size_t size字节数

 psl->array =(int*)malloc(sizeof(SLDataType)*4);

这句代码的含义是通过malloc函数返回一个指向16字节的空间的int*指针然后为了接收这个指针,我们定义了一个int *array指针,通过这个指针接收malloc的返回值
malloc 函数用于在堆上分配一块指定大小的内存空间,并返回一个指向该内存块起始地址的指针。为了接收这个指针,我们需要定义一个相应类型的指针变量并将 malloc 函数的返回值赋给它。
2、
void *realloc( void *memblock, size_t size );

   SLDataType*tmp= (int*)realloc(psl->array,sizeof(SLDataType) *psl->capacity*2);

realloc函数需要接收两个参数:第一个参数是指向原始内存块指针的指针,第二个参数是所需的新内存块大小。ps:第二个参数是新增后的字节数大小

实现步骤

1.构建结构体

typedef int SLDataType;
typedef struct SeqList
{
    SLDataType* array;
    //定义一个结构体指针,类型为SLDataType(int)
    size_t size;//当前已存储的数量
    size_t capacity;//当前最大容量
}SeqList;

2.顺序表——初始化

void SeqListInit(SeqList* psl)  
{
    assert(psl);
    断言:利于找出bug,防范指针为空
    不为空就通过,为空就报错
    psl->array =(int*)malloc(sizeof(SLDataType)*4);
    //开辟动态内存空间
    if(psl->array==NULL) //如果开辟空间失败
    {
        perror("malloc fail");//打印错误信息
        return;
    }
    psl->size = 0;
    psl->capacity = 4;
}

开辟动态内存空间:静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

3.顺序表——销毁

void SeqListDestory(SeqList* psl)
{
    assert(psl);
    free(psl->array);  
   // 通过free()函数释放指针所指向的动态分配的内存空间
    psl->array = NULL;   
    psl->size = 0;   
    psl->capacity = 0;
} 

4.顺序表——打印

void SeqListPrint(SeqList* psl)
{
    assert(psl);
    for (int start = 0; start < psl->size; start++)
    {
        printf("%d ", psl->array[start]);
    }
    printf("\n");
}

5.顺序表——扩容

void CheckCapacity(SeqList* psl)
{
    assert(psl);
    if (psl->size == psl->capacity)
   {
   SLDataType*tmp= (int*)realloc(psl->array,sizeof(SLDataType) *psl->capacity*2);
      if (tmp == NULL)  //如果开辟空间失败
        {
       perror("realloc fail");  //打印错误信息
       return;
         }  
    psl->array = tmp;
    psl->capacity *= 2;
   }

6.顺序表——插入

头插:将数组中的元素全部向后移动一位,空出第一的位置留给头插
尾插:开辟动态内存空间后,直接在最后插入元素
在任意位置插入:插入的位置为pos,将在pos位置的元素以及pos位置后的元素全部向后移动一位,用x覆盖pos处元素

顺序表头插

void SeqListInsert(SeqList* psl, int pos, SLDataType x)
{
    assert(psl);
    assert(0 <= pos && pos <= psl->size);
    //断言:保证插入的数字在内存空间内
    
    CheckCapacity(psl);
    //插入需要开辟内存空间
    for (int end = psl->size; end >= pos; end--)
    {
        psl->array[end] = psl->array[end - 1];
    }
    psl->array[pos] = x;
    psl->size++;
}

在这里插入图片描述

顺序表尾插

void SeqListPushBack(SeqList* psl, SLDataType x)
{
    assert(psl);
    CheckCapacity(psl);
    //psl->array[psl->size] = x;
    //psl->size++;
    SeqListInsert(psl, psl->size, x);
}

在这里插入图片描述

任意位置的插入

void SeqListInsert(SeqList* psl, int pos, SLDataType x)
{
    assert(psl);
    assert(0 <= pos && pos <= psl->size);
    //保证插入的数字在内存空间内
    CheckCapacity(psl);
    for (int end = psl->size; end >= pos; end--)
    {
        psl->array[end] = psl->array[end - 1];
    }
    psl->array[pos] = x;
    psl->size++;
}

在这里插入图片描述

7.顺序表——删除

头删:将第一位以后的元素全部向前移动一位,将第一位元素覆盖掉
尾删:利用size–影响数组下标,打印的时候直接会把最后一位漏掉

顺序表头删

void SeqListPopFront(SeqList* psl)
{
    assert(psl);
    assert(psl->size > 0);
    断言:当删除到个数小于0时报错
    int start = 0;
    while (start < psl->size)
    {
        psl->array[start] = psl->array[start + 1];
        start++;
    }
    psl->size--;
}

在这里插入图片描述

顺序表尾删

void SeqListPopBack(SeqList* psl)
{
    assert(psl);
    assert(psl->size > 0);//真就过,假报错、
断言:当删除到个数小于0时报错
    psl->size--;
    //直接通过size--来删去最后一个元素
}

在这里插入图片描述

8.顺序表——查找

int SeqListFind(SeqList* psl, SLDataType x)
{
    assert(psl);
 //   assert(x >=0 && x < psl->size);
    for (int start = 0; start < psl->size; start++)
    {
        if (psl->array[start] == x)
        {
            return start;
        }
    }  
    return -1;
}

9.测试用例

void test_1()
{
    SeqList a;
    SeqListInit(&a);//初始化
    CheckCapacity(&a);//检查空间
    SeqListPushBack(&a, 1);//尾插
    SeqListPushBack(&a, 2);//尾插
    SeqListPushBack(&a, 3);//尾插
    SeqListPushBack(&a, 4);//尾插
    SeqListPushBack(&a, 5);//尾插
    SeqListPrint(&a);

    SeqListPopBack(&a);//尾删
    SeqListPopBack(&a);//尾删
    SeqListPopBack(&a);//尾删
    SeqListPopBack(&a);//尾删
    SeqListPrint(&a);
    SeqListPopBack(&a);//尾删
    SeqListPrint(&a);
    //SeqListPopBack(&a);//尾删
    //SeqListPopBack(&a);//尾删

    SeqListPushBack(&a, 1);//尾插
    SeqListPushFront(&a, -1);//头插
    SeqListPushFront(&a, -2);//头插
    SeqListPushFront(&a, -3);//头插
    SeqListPushFront(&a, -4);//头插
    SeqListPrint(&a);

    SeqListPopFront(&a);//头删
    SeqListPopFront(&a);//头删
    SeqListPopFront(&a);//头删
    SeqListPopFront(&a);//头删
    SeqListPrint(&a);
    SeqListPopFront(&a);//头删
    //SeqListPopFront(&a);//头删
    //SeqListPopFront(&a);//头删
    SeqListPrint(&a);

    SeqListInsert(&a, 0, 1000);//任意插入
    SeqListPrint(&a);
    SeqListInsert(&a, 0, 1000);//任意插入
    SeqListInsert(&a, 1, -1000);//任意插入
    SeqListInsert(&a, 2, -800);//任意插入
    SeqListInsert(&a, 0, 8000);//任意插入
    SeqListPrint(&a);

    SeqListErase(&a, 0);//任意删除
    SeqListErase(&a, 0);//任意删除
    SeqListPrint(&a);
    SeqListErase(&a, 2);//任意删除
    SeqListPrint(&a);
    SeqListErase(&a, 0);//任意删除
    SeqListPrint(&a);
    SeqListErase(&a, 0);//任意删除
    SeqListPrint(&a);

    SeqListInsert(&a, 0, 8000);//任意插入
    SeqListPrint(&a);
    SeqListInsert(&a, 0, 100);//任意插入
    SeqListPrint(&a);
    SeqListInsert(&a, 1, -100);//任意插入
    SeqListPrint(&a);
    SeqListAmend(&a, 1, 2);//修改
    SeqListPrint(&a);
    SeqListAmend(&a, 0, 1);//修改
    SeqListPrint(&a);
    SeqListAmend(&a, 2, 3);//修改
    SeqListPrint(&a);

    printf("%d\n", SeqListFind(&a, 3));//查找
    printf("%d\n", SeqListFind(&a, 4));//查找

    SeqListDestory(&a);//销毁
}
void test_2()
{
    SeqList sl;//创建顺序表变量
    SeqListInit(&sl);//初始化顺序表
    SeqListPushBack(&sl, 1);//尾插
    SeqListPushBack(&sl, 2);//尾插
    SeqListPushBack(&sl, 3);//尾插
    SeqListPushFront(&sl, 0);//头插
    SeqListPrint(&sl);//打印
    SeqListPopFront(&sl);//头删
    SeqListPopBack(&sl);//尾删
    SeqListPrint(&sl);//打印
    SeqListDestory(&sl);//销毁顺序表
}
void test_3()
{
    SeqList sl;//创建顺序表变量
    SeqListInit(&sl);//初始化顺序表
    SeqListPushBack(&sl, 1);//尾插
    SeqListPushBack(&sl, 2);//尾插
    SeqListPushBack(&sl, 3);//尾插
    SeqListInsert(&sl, 0, 0);//任意插入
    SeqListInsert(&sl, 2, 10);//任意插入
    SeqListErase(&sl, 4);//任意删除
    SeqListAmend(&sl, 1, 20);//任意修改
    SeqListPrint(&sl);//打印
    SeqListDestory(&sl);//销毁
}
void test_4()
{
    SeqList sl;
    SeqListInit(&sl);//初始化
    for (int i = 0; i < 10; i++)
    {
        SeqListPushBack(&sl, i);//循环尾插
    }
    SeqListPrint(&sl);//打印
    SeqListPushBack(&sl, 10);//尾插
    SeqListPrint(&sl);//打印
    SeqListDestory(&sl);//销毁
}
void test_5()
{
    SeqList sl;
    SeqListInit(&sl);//初始化
    for (int i = 0; i < 10; i++)
    {
        SeqListPushFront(&sl, i);//循环尾插
    }
    SeqListPrint(&sl);//打印
    SeqListPushFront(&sl, 10);//头插
    SeqListPrint(&sl);//打印
    SeqListDestory(&sl);//销毁
}
void test_6()
{
    SeqList sl;
    SeqListInit(&sl);//初始化
    SeqListPushBack(&sl, 1);//尾插
    SeqListPushBack(&sl, 2);//尾插
    SeqListPushBack(&sl, 3);//尾插
    printf("%d\n", SeqListFind(&sl, 2));//查找成功
    printf("%d\n", SeqListFind(&sl, 4));//查找失败
    SeqListDestory(&sl);
}
int main()
{
    test_1();
    test_2();
    test_3();
    test_4();
    test_5();
    test_6();
    return 0;
}
posted @ 2023-04-18 18:14  Fan_558  阅读(3)  评论(0编辑  收藏  举报  来源