数据结构(顺序表)(2)
- 一个是指定位置插入数据, 一个是指定位置删除数据. 还有一些由这两个函数而牵涉到的函数.
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
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++;
}
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
}
- 当我们有了这两个函数之后, 前面写的尾插, 头插, 尾删, 头删, 都可以用这两个函数去实现.
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);
SLInsert(ps, ps->size, x);
}
void SLpopback(SL* ps)
{
assert(ps);
SLErase(ps, ps->size-1);
}
void SLpushFront(SL* ps, SLDataType x)
{
assert(ps);
SLInsert(ps, 0, x);
}
void SLpopFront(SL* ps)
{
assert(ps);
SLErase(ps, 0);
}
- 而且以后如果要用c语言写顺序表, 也是这样写, 先把指定位置插入删除, 这两个函数写好之后, 就可以复用这两个函数到别的功能去了.
- 然后就还有函数, 算是锦上添花吧, 不过也无伤大雅.
- 一个是修改下标为pos的值为x
void SLModify(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
ps->a[pos] = x;
}
- 有同学觉得这个函数没什么必要, 要这样直接在主函数代码文件写一句
sa.a[1] = 2;
(这个是我的一个例子,可以看下面的图片,就知道了.) 这样不就可以了吗, 不过写函数有个好处是什么呢, 函数里面有更多的判断条件, 代码就更稳妥些, 如果单单只是一个语句, 可能后面有人用你的代码的时候, 没有理解好你的代码, 把你的代码改了改, 不是如下这样写:
- 对吧, 所以用函数还能检测出来是不是非空指针. 所以有时候是能用函数就用函数.
- 还有最后一个函数, 这个函数主要是拿来配合指定位置插入数据和指定位置删除数据用的. 作用就是找到值为x的下标, 这样就多了一种玩法, 就可以直接你想删什么数值就删什么数值, 不用去想下标是多少了. 大概就这么一个作用.
int SLFind(SL* ps, SLDataType x)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
if (ps->a [i] == x)
{
return i;
}
}
return -1;
}
- OK, 那顺序表这部分就已经讲完了, 下面是全部的代码:
- 先是头文件的Seqlist.h
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLDataType;
typedef struct Seqlist
{
SLDataType* a;
int size;
int capacity;
}SL;
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
void SLCheckCapacity(SL* ps);
void SLPushBack(SL* ps, SLDataType x);
void SLpopback(SL* ps);
void SLpushFront(SL* ps, SLDataType x);
void SLpopFront(SL* ps);
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
void SLModify(SL* ps, int pos, SLDataType x);
int SLFind(SL* ps, SLDataType x);
#include"Seqlist.h"
void SLInit(SL* ps)
{
ps->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);
if (ps->a == NULL)
{
perror("malloc failed");
exit(-1);
}
ps->size = 0;
ps->capacity = 4;
}
void SLDestroy(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
void SLPrint(SL* ps)
{
for (int i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
void SLCheckCapacity(SL* ps)
{
if (ps->size == ps->capacity)
{
SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));
if (tmp == NULL)
{
perror("relloc failed");
exit(-1);
}
ps->a = tmp;
ps->capacity *= 2;
}
}
void SLPushBack(SL* ps, SLDataType x)
{
SLCheckCapacity(ps);
ps->a[ps->size] = x;
ps->size++;
}
void SLpopback(SL* ps)
{
assert(ps->size > 0);
ps->size--;
}
void SLpushFront(SL* ps, SLDataType x)
{
SLCheckCapacity(&ps);
int end = ps->size - 1;
for(int i = end; i >= 0;i--)
{
ps->a[i + 1] = ps->a[i];
}
ps->a[0] = x;
ps->size++;
}
void SLpopFront(SL* ps)
{
assert(ps);
assert(ps->size > 0);
int begin = 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
}
int SLFind(SL* ps, SLDataType x)
{
assert(ps);
for (int i = 0; i < ps->size; i++)
{
if (ps->a [i] == x)
{
return i;
}
}
return -1;
}
void SLInsert(SL* ps, int pos, SLDataType x)
{
assert(ps);
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++;
}
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
}
void SLModify(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);
ps->a[pos] = x;
}
- 下面是测试代码, 可看可不看, 无伤大雅: test.c
#include"Seqlist.h"
int main()
{
SL sa;
SLInit(&sa);
SLPushBack(&sa, 1);
SLPushBack(&sa, 2);
SLPushBack(&sa, 3);
SLPushBack(&sa, 4);
SLPushBack(&sa, 5);
SLPrint(&sa);
return 0;
}