顺序表定义及实现

167 阅读4分钟

一、顺序表的定义

  • 在计算机内存中,顺序表可以以数组的形式来保存,也可以分配一段地址连续的存储单元来保存数据。
  • 可以采用动态分配和静态分配的方式为顺序表分配空间。

(一)顺序表的存储

  1. 存储行为:一段连续的存储单元
  2. 存储位置:栈,堆,数据区,代码区 注意:
  • 顺序表存储在栈上时,由操作系统和编译器来分配空间,不能由程序员手动控制,不支持扩容。栈的生命周期:函数内,函数返回后,栈中的内容就会消失。
  • 顺序表存储在堆上时,由程序员使用malloc申请空间,free释放空间,支持扩容。堆的生命周期:由malloc开始到free结束。
  1. 那顺序表该定义在栈上还是堆上呢? 取决于你的需求。如果你想支持扩容,就定义在堆上。如果你想不支持扩容,就定义在栈上。

(二)顺序表中的结构

image

如图所示,在定义顺序表时,需要定义一个表头。表头里要定义一个data指针,用来存储数据空间首地址。还要定义两个变量pos和capacity;pos指向顺序表中待插入位置;capacity表示顺序表的最大容量。如果pos等于capacity,这时顺序表已满,如果继续插入元素,就需要扩容了。

二、顺序表的操作

(一)定义顺序表表头

typedef int Element;
typedef struct {
	Element *data; //存储数据空间首地址
	int pos;  //指向待插入的位置
	int capacity; //顺序表的最大存储容量
}seqTable;

(二)创建顺序表

/*在测试函数中调用createSeqTable函数,是为了创建一个顺序表,
然后拿这个表去进行其他操作,所以返回值应是seqTable.
参数n决定数据空间有多少个元素。
*/
seqTable* createSeqTable(int n){
    //先定义一个空表头
    seqTable *table = NULL;
    table = malloc(sizeof(seqTable));
    if(table == NULL){
        printf("malloc failed\n");
        return NULL;
    }
    //申请数据空间
    table->data = malloc(sizeof(Element)*n);
    if(table->data == NULL){
        printf("data malloc failed\n");
        free(table);
        return NULL;
    }
    table->capacity = n;
    table->pos = 0;
    return table;
}

(三)顺序表的插入

//在尾插法和指定位置插入时,可能会多次扩容,可以单独将其定义为一个函数enlarger
static int enlarger(seqTable *table){
    //1.申请需要扩容的空间,可以是两倍扩容:table->capacity*2 ,三倍扩容:table->capacity*3
    seqTable *tmp = malloc(sizeof(Element)* table->capacity *2);
    //2.检查申请的新空间是否申请成功
    if(tmp == NULL){
        printf("tmp malloc failed\n");
        return -1;
    }
    //3.将老空间里的内容拷贝到新空间
    memcpy(tmp,table,sizeof(Element)*table->pos);
    //4.释放掉老空间,修改表头里的capacity和数据空间
    free(table);
    table->data = tmp;
    table->capacity *= 2;
    return 0;

}
//尾插法
int pushbackSeqTable(seqTable *table, Element value) {
    //1.可以先判断一下传进来的顺序表是否为空
    if(table == NULL){
        printf("table is null\n");
        return -1;
    }
    //2.插入之前,要考虑顺序表空间是否足够,不够的话需要进行扩容
    if(table->pos >= table->capacity){
        if(enlarger(table)){
            printf("enlarger failed\n");
        }
    }
    //3.为新空间赋值
    table->data[table->pos] = value;
    ++table->pos;
    return 0;

}
//指定位置插入
int insertPosSeqTable(seqTable *table, int index, Element value) {
    //1.判断下标index是否越界
    if(index < 0 || index > table->capacity){
        printf("index overstep the boundary\n");
        return -1;
    }

    //2.在插入元素之前,检查一下是否需要扩容空间
    if(index >= table->capacity && enlarger(&table)){
        printf("enlarger table failed\n");
        return -1;
    }

    //3.任意位置插入时,把要插入位置后面的元素从后往前一个一个移动。
    // 注意:表头中的pos指向的是待插入位置,此时pos位置是没有数据的,pos-1处才有数据,所以应从pos-1处开始往后搬
    for(int i = table->pos-1;i >= index;--i){
        table->data[i+1] = table->data[i];
    }

    //4.更改插入元素位置的值
    table->data[index] = value;
    ++table->pos;
    return 0;
}

(四) 顺序表的删除

int findIndex(const seqTable *table,Element value){
    for(int i = 0;i<table->pos;i++){
        if(table->data[i] == value){
            return i;
        }
    }
    return -1;
}

//按值删除元素
int deleteSeqTable(seqTable *table, Element value) {
    //1.查找待删除的数据value在数据空间的位置
    int index = findIndex(table,value);
    if(index == -1){
        printf("not find %d element\n",value);
        return -1;
    }
    //2.删除value值,删除方法:从index+1 开始到pos,从前往后一个一个的移动
    for(int i = index+1;i<= table->pos;i++){
        table->data[i-1] = table->data[i];
    }
    --table->pos;
    return 0;
}

(五) 顺序表表头的释放

void releaseSeqTable(seqTable *table) {
    if(table){
        if(table->data){
            free(table->data);
        }
        free(table);
    }
}

(六)显示顺序表

void showSeqTable(const seqTable *table) {
    //1.检查table顺序表是否为空
    if(table == NULL){
        return ;
    }
    for(int i = 0;i<table->pos;i++){
        printf("the element is %d\t",table->data[i]);
    }

}