【数据结构】线性表之顺序表的实现

                                

目录

   顺序表的概念及结构

   顺序表的实现

初始化顺序表

顺序表的增加

尾插

头插

顺序表的删除

尾删

头删

销毁顺序表

顺序表查找

在pos位置插入元素

在pos位置删除元素

说明

整合源代码



   顺序表的概念及结构

             顺序表:指的是用一组地址连续的存储单元依次存储线性表的数据元素。一般情况下采            用数组存储,在数组上完成数据的增删查改

             顺序表一般可以分为静态顺序表动态顺序表

              静态顺序表---使用定长数组存储元素。分配的空间长度是固定的,表一旦空间不足时不            能扩充。

        存储结构类型定义:

              

       动态顺序表---使用动态开辟的数组存储。分配的空间长度大小是可变的,当空间不足时可进行再次分配,即可自由扩充空间大小。

存储类型定义:

          

       静态顺序表只适用于确定知道需要存多少数据的场景,静态顺序表的定长数组分配的空间长度是固定的,不能自由扩充,可能存在浪费或不够用。因此,现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以我们实现动态顺序表。

顺序表的实现

        当在一些大型项目中,分模块进行是比较常见的,因此,顺序表的实现就采用分模块的方式.

  顺序表的实现需要分两个模块:SeqList.hSeqList.c

SeqList.h       //函数的声明及类型的定义

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

typedef int SLDateType;
//动态顺序表
typedef struct SeqList
{
	SLDateType* a;
	int size;        //当前有效元素的个数
	int capacity;    //当前分配的最大存储容量
}SeqList;


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

//销毁顺序表
void SeqListDestroy(SeqList* ps);

//顺序表的增加
//尾插、尾删
void SeqListPushBack(SeqList* ps, SLDateType x);
void SeqListPopBack(SeqList* ps);

//头插、头删
void SeqListPushFront(SeqList* ps, SLDateType x);
void SeqListPopFront(SeqList* ps);



// 顺序表查找
//找到返回下标、找不到返回-1
int SeqListFind(SeqList* ps, SLDateType x);

// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x);

// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos);


SeqList.c      //函数的实现

初始化顺序表

      初始化时预先给表分配一些空间

void SeqListInit(SeqList* ps)
{
    assert(ps);  //防止为空指针
    ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);//动态开辟数组空间
    if (ps->a == NULL)
    {
        perror("malloc failed");
        exit(-1);
    }
    ps->size = 0;     //当前有效元素个数初始化为0
    ps->capacity = 4; //当前起始最大限度存储容量先设为4
}

顺序表的增加

     尾插

       此时比较简便,直接在size个元素后插入即可。 但在插入元素当前空间是否已满,此时采用封装一个检查容量并增容的函数,直接调用此函数判断是否空间已满,后面用起来比较方便。

//检查容量并增容
void SLCheckCapacity(SeqList* ps)
{
    assert(ps);
    if (ps->size == ps->capacity)
    {
        SLDateType* pt = (SLDateType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDateType));
        if (pt == NULL)
        {
            perror("realloc failed");
            exit(-1);
        }
        ps->a = pt;
        ps->capacity *= 2;
    }
}


//尾插
void SeqListPushBack(SeqList* ps, SLDateType x)
{
    SLCheckCapacity(ps);  //判断空间是否满了,若满则扩容
    ps->a[ps->size] = x;  //插入值为x的元素
    ps->size++;           //元素个数加一
}

  头插

     在插入元素之前需要判满。比起尾插较麻烦一些,要从尾部开始size个元素依次往后挪

//头插
void SeqListPushFront(SeqList* ps, SLDateType 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++;
}

顺序表的删除

      尾删

     在删除元素之前,需要先判断当前是否为空,这里使用assert来检查,这是一种严格的检查,相比if判断比较暴力,若元素为空直接终止并提示程序异常。if也可判断

//尾删
void SeqListPopBack(SeqList* ps)
{
    assert(ps);
    assert(ps->size > 0); //检查是否为空,为空程序异常报错,这是比较严格的检查;也可用if来判断
    ps->size--;           //元素个数减一
}

    头删

    同样需要先进行检查是否为空,检查方式同上。

//头删
void SeqListPopFront(SeqList* ps)
{
    assert(ps);
    assert(ps->size > 0); //检查是否为空
    int start = 1;  //首元素的位置
    //后面size-1个元素依次向前覆盖
    while (start < ps->size)
    {
        ps->a[start - 1] = ps->a[start];
        start++;
    }
    //元素个数减一
    ps->size--;
}

销毁顺序表

//顺序表的销毁
void SeqListDestroy(SeqList* ps)
{
    assert(ps);
    free(ps->a);   //释放动态开辟的数组
    ps->a = NULL;
    ps->capacity = ps->size = 0;  
}

顺序表查找

      查找值为x的元素,找到了就返回元素所在的下标,找不到返回-1。

//顺序表的查找
int SeqListFind(SeqList* ps, SLDateType x)
{
    assert(ps);
    int i = 0;
    //查找值为x的元素,找到返回其下标,否则返回-1
    for (i = 0; i < ps->size; i++)
    {
        if (ps->a[i] == x)
            return i;
    }
    return -1;
}

在pos位置插入元素

       

     在插入元素之前,需要检查插入位置是否合法以及当前空间容量。

// 在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x)
{
    assert(pos >= 0 && pos <= ps->size); //位置是否合法
    SLCheckCapacity(ps);                 //判断当前容量是否为空
    int end = ps->size - 1;              //尾元素的位置
    //pos位置及其后面的元素依次后挪 
    while (end >= pos)
    {
        ps->a[end + 1] = ps->a[end];
        end--;
    }
    ps->a[pos] = x;       //在插入位置插入元素x
    ps->size++;           //元素个数加一             
}

在pos位置删除元素

       

    同样注意删除前要判断插入位置是否合法

// 在pos位置删除x
void SeqListErase(SeqList* ps, int pos)
{
    assert(pos >= 0 && pos < ps->size); //插入位置是否合法
    int start = pos + 1;                //找到要删除元素位置后一个元素的位置
    //pos位置后面的元素依次向前覆盖
    while (start < ps->size)
    {
        ps->a[start - 1] = ps->a[start];
        start++;
    }
    ps->size--;     //元素个数减一
}

说明

      前面的头插尾插、头删尾删都可附用以上两段代码,在插入和删除时无伦头插头删、尾插尾删或者只要是插入和删除操作均可,即插入和删除通用代码,用时直接调用即可

整合源代码

//SeqList.h

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

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	int size;        
	int capacity;    
}SeqList;


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

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

//销毁顺序表
void SeqListDestroy(SeqList* ps);

//顺序表的增加
//尾插、尾删
void SeqListPushBack(SeqList* ps, SLDateType x);
void SeqListPopBack(SeqList* ps);

//头插、头删
void SeqListPushFront(SeqList* ps, SLDateType x);
void SeqListPopFront(SeqList* ps);

// 顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);

// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x);

// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos);



//SeqList.c

#include "SeqList.h"

void SeqListInit(SeqList* ps)
{
    assert(ps);
    ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);
    if (ps->a == NULL)
    {
        perror("malloc failed");
        exit(-1);
    }
    ps->size = 0;
    ps->capacity = 4;
}


//检查容量并增容
void SLCheckCapacity(SeqList* ps)
{
    assert(ps);
    if (ps->size == ps->capacity)
    {
        SLDateType* pt = (SLDateType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDateType));
        if (pt == NULL)
        {
            perror("realloc failed");
            exit(-1);
        }
        ps->a = pt;
        ps->capacity *= 2;
    }
}


//顺序表增添数据
//尾插
void SeqListPushBack(SeqList* ps, SLDateType x)
{
    SLCheckCapacity(ps);
    ps->a[ps->size] = x;
    ps->size++;
}

//尾删
void SeqListPopBack(SeqList* ps)
{
    assert(ps);
    assert(ps->size > 0); 
    ps->size--;           
}

//头插
void SeqListPushFront(SeqList* ps, SLDateType 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++;
}

//头删
void SeqListPopFront(SeqList* ps)
{
    assert(ps);
    assert(ps->size > 0); 
    int start = 1;  
    while (start < ps->size)
    {
        ps->a[start - 1] = ps->a[start];
        start++;
    }
    ps->size--;
}


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


//顺序表的查找
int SeqListFind(SeqList* ps, SLDateType x)
{
    assert(ps);
    int i = 0;
    for (i = 0; i < ps->size; i++)
    {
        if (ps->a[i] == x)
            return i;
    }
    return -1;
}



// 在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x)
{
    assert(pos >= 0 && pos <= ps->size); 
    SLCheckCapacity(ps);                 
    int end = ps->size - 1;              
    while (end >= pos)
    {
        ps->a[end + 1] = ps->a[end];
        end--;
    }
    ps->a[pos] = x;       
    ps->size++;                       
}

// 在pos位置删除x
void SeqListErase(SeqList* ps, int pos)
{
    assert(pos >= 0 && pos < ps->size); 
    int start = pos + 1;               
    while (start < ps->size)
    {
        ps->a[start - 1] = ps->a[start];
        start++;
    }
    ps->size--;     
}

  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值