顺序表 (1)

顺序表Sequence list
其实就是一个数组。

物理地址连续。但对比起一般数组来说,顺序表的数据必须是从第一个位置开始连续存储,紧挨着放,不能间隔放。

数据结构:帮助我们更好地管理数据——增删查改

基本结构SeqList

//定义在.h文件中。
typedef int SLDataType;

typedef struct SeqList{
    SLDataType* a;//指向动态数组的指针。
    int size;//顺序表的有效数据个数。
    int capacity;//容量--空间大小。因为扩容时一般不会只扩一个,会一次扩多几个。
}SL;


检查容量CheckCapacity

当size和capacity相等时,有2种情况:一种是它们都为0,则此时直接给一个一定的容量,比如4,另一种是数据到达容量值时即size=capacity时,扩容2倍(也可以按其他规则扩容)。

void CheckCapacity(SL* ps){
    assert(ps != NULL);
    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 failed.\n");
            exit(-1);//realloc失败一般就是没内存了。可以直接退出程序。这种情况遇到的比较少。
        }

        ps->a = tmp;
        ps->capacity = newCapacity;
    }
}


打印所有数据SLPrint

void SLPrint(SL* ps){
    assert(ps != NULL);
    for (int i = 0; i < ps->size; i++){
        printf("%d ", ps->a[i]);
    }
    printf("\n");
}
0.3 销毁顺序表SLDestroy
void SLDestroy(SL* ps){
    assert(ps != NULL);
    if(ps->a){
        free(ps->a);
        ps->a = NULL;
        ps->size = ps->capacity = 0;
    }
}


初始化SLInit

void SLInit(SL* ps){
    assert(ps != NULL);//防御式编程。防止他人不小心传个空指针过来。
    ps->a = NULL;
    ps->size = ps->capacity = 0;
}


尾插数据PushBack

void SLPushBack(SL* ps, SLDataType x){
    assert(ps != NULL);
    //插入数据x之前,要先检查容量空间
    CheckCapacity(ps);

    ps->a[ps->size] = x;
    ps->size++;
}


尾删数据PopBack

void SLPopBack(SL* ps){
    assert(ps != NULL);
    //要对size进行检查,防止size变为负数,
    //如果size变为负数,后续PushBack时会造成越界访问。
    //注:越界的过程不一定会报错,但在SLDestroy的free时会报错。
    assert(ps->size > 0);//当size等于0时,直接报错。
    ps->size--;
}

//或者检查时温柔一点
void SLPopBack(SL* ps){
    assert(ps != NULL);
    if(ps->size == 0){
        printf("The Sequence List is empty.\n");
        return;
    }
    ps->size--;
}

头插数据PushFront

void SLPushFront(SL* ps, SLDataType x){
    assert(ps != NULL);
    CheckCapacity(ps);

    //将所有数据往后挪动1个单位。
    int end = ps->size - 1;
    while (end >= 0){
        ps->a[end + 1] = ps->a[end];
        --end;
    }

    ps->a[0] = x;
    ps->size++;
}


头删数据PopFront

向前覆盖

void SLPopFront(SL* ps){
    assert(ps != NULL);
    int begin = 1;
    while(begin < ps->size){
        ps->a[begin - 1] = ps->a[begin];
        ++begin;
    }
    ps->size--;
}


顺序表中,尾插尾删的时间复杂度为O(1),头插头删的时间复杂度是O(N)。

任意位置插入SLInsert

void SLInsert(SL* ps, int pos, SLDataType x){
    assert(ps != NULL);
    assert(pos >= 0 && pos <= ps->size);

    SLCheckCapacity(ps);

    //把pos位置后的所有数字往后挪一个单位。
    int end = ps->size;
    while (end >= pos){
        ps->a[end] = ps->a[end - 1];
        end--;
    }

    ps->a[pos] = x;
    ps->size++;
}


实现了SLInsert,可以给PushBack和PushFront复用。

void SLPushBack(SL* ps, SLDataType x){
    SLInsert(ps, ps->size, x);
}

void SLPushFront(SL* ps, SLDataType x){
    SLInsert(ps, 0, x);
}


任意位置删除SLErase

void SLErase(SL* ps, int pos){
    assert(ps != NULL);
    assert(pos >= 0 && pos < ps->size);

    //将pos后的数据往前挪动
    int begin = pos;
    while (begin < ps->size - 1){
        ps->a[begin] = ps->a[begin + 1];
        begin++;
    }
    ps->size--;
}


实现了SLErase,可以给PopBack和PopFront复用。

void SLPopBack(SL* ps){
    SLErase(ps, ps->size - 1);
}

void SLPopFront(SL* ps){
    SLErase(ps, 0);
}


查找SLSearch

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


修改SLModify

void SLModify(SL*ps, int pos, SLDataType x){
    assert(ps != NULL);
    assert(pos >= 0 && pos < ps->size);
    ps->a[pos] = x;
}

注意事项

越界不一定报错,例如以下程序在VS2013下就不会报错。
系统对越界的检查是设岗抽查,只检查一部分,比如下面的arr[10]就会报错。

int main(){
    int arr[10];
    //arr[10] = 1;
    arr[12] = 1;
    arr[15] = 1;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

裙下的霸气

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

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

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

打赏作者

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

抵扣说明:

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

余额充值