顺序表的定义,增删改查

顺序表的特点

1)随机访问:即可在o(1)时间内找到第i个元素。 {data[i-1]}

2)存储密度高,每个结点只存储数据元素

3)拓展容量不方便

4)插入,删除不方便

一,顺序表的定义

1)静态分配内存空间

//静态分配数组(无法改变顺序表大小)
#define MaxSize 10
typedef struct {
    int data[MaxSize];
    int length;
}SqlList;   //顺序表的定义类型

//初始化一个顺序表
void InitList(SqlList& L) {
    for (int i = 0; i <= MaxSize; i++) {
        L.data[i] = 0;  

//初始化所有数据元素设置为默认初始值0,若不初始化初始值则会出现脏数据。
    }

   L.length = 0;    //顺序表初始长度为0;
}

2),动态分配

//动态分配
#define InitSize 10   //顺序表初始长度

//声明顺序表
typedef struct {
    int* data;       //指示动态分配数组的指针,指向顺序表中第一个元素的地址
    int MaxSize;    //最大容量
    int length;     //当前容量 
}SeqList;
//初始化
void InitList(SeqList& L) {
    //用malloc函数申请一篇连续的存储空间,其大小为  顺序表初始长度 * 元素数据类型大小
    L.data = (int *)malloc(InitSize*sizeof(int));
    L.length = 0;
    L.MaxSize = InitSize;
}
//增加动态数组长度
void IncreaseSize(SeqList& L, int len) {
    int* p = L.data;
    L.data = (int*)malloc((L.MaxSize + len) * sizeof(int));
    for (int i = 0; i < L.length; i++) {
        L.data[i] = p[i];   //将数据复制到新的空间
    }
    L.MaxSize = L.MaxSize + len;
    free(p); //释放内存(老指针指向的内存空间)
    //通过分配一块新的空间将原指针指向新的空间,再把久的数据复制到新的空间中即可。
}
int main() {
    SeqList L;
    InitList(L);
    IncreaseSize(L, 5);
    return 0;
}

 

总结

二,顺序表的插入删除(基于静态分配的)

1)插入

ListInsert(&L,i,e):在顺序表L中的第i个位置上插入元素e

逻辑:将第i个元素和之后的元素都往后移动一位,并将新的元素赋值给data[i-1];

代码

void ListInsert(SqList &L, int i, int e) {
    for (int j = L.length; j >= 1; j--) {
        L.data[j] = L.data[j - 1];
    }
    L.data[i - 1] = e;
    L.length++;
}

 

*但i的值可能不合法,所以需要对i进行合法性判断。

改进的代码:

bool ListInsert(SqList &L, int i, int e) {
    //判断i是否合法
    if (L.length >= MaxSize) {
        printf("顺序表已经达到最大值");
        return false;
    }
    else if (i<1||i>L.length+1) {
        printf("i不合法");
        return false;
    }
    else
    {   //将第i个元素和之后的元素都往后移动一位,并将新的元素赋值给data[i-1];
        for (int j = L.length; j >= 1; j--) {
            L.data[j] = L.data[j - 1];
        }
        L.data[i - 1] = e;
        L.length++;
        return true;
    }

时间复杂度分析

最好的情况:插入元素在顺序表表尾 i =L.length+1。此时时间复杂度为o(1);

最坏的情况:新元素插在表头i=1。即原表中所有的元素都要后移一位,for循环需要循环n = L.length次。此时时间复杂度为o(n);

平均情况:假设新元素到任何一个位置的概率都是相同的,即i=1,2,3,,,,length+1的概率都是p = 1/(n+1)。

所以平均循环次数 = p*{(n)+(n-1)+......1+0} = {n(n+1)/2}*1/(n+1) = n/2。

 

2)顺序表的删除

bool ListDelete(SqList &L, int i, int &e) {    //这里使用的&L表示在原顺序表的地址上操作,不会复制另一个相同的顺序表
    //判断i是否合法
    if (i < 1 || i>L.length) {
        //i不能<1且不能大于表长
        return false;
    }
    else {
        //将删除的元素赋值给e
        e = L.data[i - 1];
        //顺序表的删除:将i个元素之后的元素都往前移动一位。
        for (int j = i; j < L.length; j++) {
            L.data[j - 1] = L.data[j];
        }

        L.length--;
        return true;
    }
}

 删除操作的时间复杂度分析:

最好的情况:删除最后一个元素:for循环执行循环0次,时间复杂度为o(1).

最坏的情况:删除第一个元素:for循环执行循环n = L.length次,时间复杂度为o(n)。

平均的情况:同样删除每个元素的概率为p = 1/n。

则平均的循环次数为 = p*{(n) + (n-1)+......1+0} = (n-1)/2

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值