数据结构之顺序表

顺序表就是数组,但是在数组的基础上,它要求数据是从头开始并且连续存储的,不能间隔存储

静态顺序表

静态顺序表中如果数据满了则不让继续存储,因此我们无法确定该给它多少内存

其头文件:

#pragma once
#define N 1000
typedef int SLDataType

//静态顺序表 
typedef struct SeqList
{
	SLDataType a[N];
	int size;//表示数组中存储了多少个数据 
 }SL; 
 
 //接口函数 
 void SeqListInit(SL* ps);
  
 void SeqListPushBack(SL* ps,SLDataType x);
 void SeqListPopBack(SL* ps);
 void SeqListPushFront(SL* ps,SLDataType x);
 void SeqListPopFront(SL* ps);
  

动态顺序表

动态顺序表:

typedef int SLDataType;

//动态顺序表 
typedef struct SeqList
{
	SLDataType* a;
	int size;//表示数组中存储了多少个数据 
	int capacity;//表示数组时间能存储多少个数据 
 }SL; 

各接口函数实现

顺序表初始化:

void SeqListInit(SL *ps)//顺序表初始化 
 {
 	ps->a = NULL;
 	ps->size = ps->capacity = 0;
 }

顺序表销毁:

void SeqListDestory(SL* ps)
{
    free(ps->a);
    ps->a = NULL;
    ps->capacity = ps->size = 0;
}

顺序表检查内存空间是否足够:

void SeqListCheckCapacity(SL* ps)//检查内存空间是否足够
{
    if (ps->size == ps->capacity)//没有空间或者空间不足的情况下
    {
        int newcapacity = ps->capacity = 0 ? 4 : ps->capacity * 2;
        SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));//没有空间则申请内存空间,有则进行扩容
        if (tmp == NULL)
        {
            printf("realloc fail \n");
            exit(-1);
        }
        ps->a = tmp;
        ps->capacity = newcapacity;
    }
}

顺序表尾插:

尾插时需考虑三种情况:

  1. 整个顺序表没有空间
  2. 空间不够,需要扩容
  3. 空间足够,直接插入数据
void SeqListPushBack(SL* ps, SLDataType x)//顺序表尾插
{
    SeqListCheckCapacity(ps);
    ps->a[ps->size] = x;
    ps->size++;
}

顺序表尾插:

void SeqListPopBack(SL* ps)//数据表尾删
{
    if(ps->size > 0)
    {
        ps->size--;
    }
}

顺序表头插:

void SeqListPushFront(SL* ps, SLDataType x)//顺序表头插
{
    SeqListCheckCapacity(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(SL* ps)
{
    assert(ps->size > 0);//存储数据不能为零,否则会终止
    int begin = 1;
    while(begin < ps->size)//数据向前挪动
    {
        ps->a[begin-1] = ps->a[begin];
        begin++;
    }
    ps->size--;
}

使用assert方法时需导入assert库

顺序表中查找数据位置(找到了返回数据位置下标,没有找到则返回-1):

int SeqListFind(SL* ps,SLDataType x)
{
    for(int i = 0;i < ps->size;i++)
    {
        if(ps->a[i] == x)
        {
            return i;
        }
    }
    return -1;
}

顺序表指定位置插入:

void SeqListInsert(SL* ps,int pos,SLDataType x)
{
    if(pos > ps->size || pos < 0)
    {
        printf("pos invalid \n")
        return ;
    }
    
    //assert(pos <= ps->size && pos => 0)//暴力方法不得输入非法pos
    SeqListCheckCapcaity(ps);
    int end = ps->size-1;
    while(end >= pos)
    {
        ps->a[end+1] = ps->a[end];
        end--;
    }
    ps->a[pos] = x;
    ps->size++;
}

顺序表指定位置删除:

void SeqListErase(SL* ps,int pos)
{
    if(pos > ps->size || pos < 0)
    {
        printf("pos invalid \n")
        return ;
    }
    int begin = pos + 1;
    while(begin < ps->size)
    {
        ps->a[begin-1] = ps->a[begin];
        begin++;
    }
    ps->size--;
}

通过顺序表的指定位置删除我们可以改善顺序表的头删

动态顺序表(完整版)

头文件:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDataType;

//动态顺序表
typedef struct SeqList
{
	SLDataType* a;
	int size;//表示数组中存储了多少个数据
	int capacity;//表示数组时间能存储多少个数据
}SL;

//接口函数
void SeqListInit(SL* ps);
void SeqListDestory(SL* ps);
void SeqListPrint(SL* ps);
void SeqListPushBack(SL* ps, SLDataType x);
void SeqListPopBack(SL* ps);
void SeqListPushFront(SL* ps, SLDataType x);
void SeqListPopFront(SL* ps);
void SeqListCheckCapcaity(SL* ps);

int SeqListFind(SL* ps,SLDataType x);
void SeqListInsert(SL* ps,int pos,SLDataType x);
void SeqListErase(SL* ps,int pos);

接口函数以及结构体的.c文件:

#include "SeqList.h"

void SeqListInit(SL* ps)//顺序表初始化
{
    ps->a = NULL;
    ps->size = ps->capacity = 0;
}

void SeqListDestory(SL* ps)
{
    free(ps->a);
    ps->a = NULL;
    ps->capacity = ps->size = 0;
}

void SeqListPrint(SL* ps)//顺序表销毁
{
    for(int i = 0; i < ps->size; i++)
    {
        printf("%d ", ps->a[i]);
    }
    printf("\n");
}

void SeqListCheckCapacity(SL* ps)//检查内存空间是否足够
{
    if (ps->size == ps->capacity)//没有空间或者空间不足的情况下
    {
        int newcapacity = ps->capacity = 0 ? 4 : ps->capacity * 2;
        SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));//没有空间则申请内存空间,有则进行扩容
        if (tmp == NULL)
        {
            printf("realloc fail \n");
            exit(-1);
        }
        ps->a = tmp;
        ps->capacity = newcapacity;
    }
}

void SeqListPushBack(SL* ps, SLDataType x)//顺序表尾插
{
    SeqListCheckCapacity(ps);
    ps->a[ps->size] = x;
    ps->size++;
}

void SeqListPopBack(SL* ps)//数据表尾删
{
    if(ps->size > 0)
    {
        ps->size--;
    }
}

void SeqListPushFront(SL* ps, SLDataType x)//顺序表头插
{
    SeqListCheckCapacity(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(SL* ps)
{
    assert(ps->size > 0);//存储数据不能为零,否则会终止
    int begin = 1;
    while(begin < ps->size)//数据向前挪动
    {
        ps->a[begin-1] = ps->a[begin];
        begin++;
    }
    ps->size--;
}

int SeqListFind(SL* ps,SLDataType x)
{
    for(int i = 0;i < ps->size;i++)
    {
        if(ps->a[i] == x)
        {
            return i;
        }
    }
    return -1;
}

void SeqListInsert(SL* ps,int pos,SLDataType x)
{
    if(pos > ps->size || pos < 0)
    {
        printf("pos invalid \n");
        return ;
    }

    //assert(pos <= ps->size && pos => 0)//暴力方法不得输入非法pos
    SeqListCheckCapacity(ps);
    int end = ps->size-1;
    while(end >= pos)
    {
        ps->a[end+1] = ps->a[end];
        end--;
    }
    ps->a[pos] = x;
    ps->size++;
}

void SeqListErase(SL* ps,int pos)
{
    if(pos > ps->size || pos < 0)
    {
        printf("pos invalid \n");
        return ;
    }
    int begin = pos + 1;
    while(begin < ps->size)
    {
        ps->a[begin-1] = ps->a[begin];
        begin++;
    }
    ps->size--;
}

测试顺序表的.c文件:

#include "SeqList.h"

void TestSeqList1() {
	SL s1;
	SeqListInit(&s1);
	SeqListPushBack(&s1, 1);
	SeqListPushBack(&s1, 2);
	SeqListPushBack(&s1, 3);
	SeqListPopBack(&s1);
	SeqListPopBack(&s1);

	SeqListPrint(&s1);
	SeqListDestory(&s1);
}

void TestSeqList2()
{
    SL s1;
	SeqListInit(&s1);
    SeqListPushBack(&s1,1);
    SeqListPushBack(&s1,2);
    SeqListPushBack(&s1,3);
    SeqListPushBack(&s1,4);
    SeqListPushBack(&s1,5);

    SeqListPushFront(&s1,10);
    SeqListPushFront(&s1,20);
    SeqListPushFront(&s1,30);
    SeqListPushFront(&s1,40);
    SeqListPushFront(&s1,50);
    SeqListPushFront(&s1,60);
    SeqListPushFront(&s1,70);

    SeqListPopFront(&s1);
    SeqListPopFront(&s1);
    SeqListPopFront(&s1);
    SeqListPopFront(&s1);

    SeqListPrint(&s1);
	SeqListDestory(&s1);
}

void TestSeqList3()
{
    SL s1;
	SeqListInit(&s1);
    SeqListPushBack(&s1,1);
    SeqListPushBack(&s1,2);
    SeqListPushBack(&s1,3);
    SeqListPushBack(&s1,4);
    SeqListPushBack(&s1,5);

    SeqListInsert(&s1,1,10);
    SeqListInsert(&s1,2,200);
    SeqListErase(&s1,5);
    SeqListErase(&s1,2);

    SeqListPrint(&s1);

    int pos = SeqListFind(&s1,5);
    printf("%d",pos);

	SeqListDestory(&s1);
}


int main() {
    TestSeqList1();
    TestSeqList2();
	TestSeqList3();

	return 0;
}

顺序表缺点:

  1. 空间不够时需要扩容,而扩容需要付出代价。扩容时当内存后面有足够空间时会原地扩容,没有足够空间时会重新找一块内存申请空间
  2. 为了避免频繁扩容,当内存空间满了时,基本都是扩容两倍,这就可能导致内存一定空间的浪费
  3. 顺序表要求从头开始连续存储数据,因此我们在头部或中间插入删除数据时就需要挪动数据,效率不高

顺序表优点:

  1. 存储密度大
  2. 可随机存取某一元素

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魏大橙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值