目录
目录
1.什么是顺序表
顺序表就是数组,用一个对应数据类型的指针,这个指针指向一个动态开辟的内存空间,该数组的的数据类型由使用者决定(一般是结构体)。
- 顺序表的优点:能够快速的尾插和尾插。
- 顺序表的缺点:头插头删速度较慢,因为要挪动数据。
2.顺序表的模拟实现(C语言)
2.1 代码简介
-
SeqList.h 头文件和函数名的声明
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<errno.h>
typedef int SLDatatype;
//因为data存储的是开辟数组的首元素的地址,data和arr都是整形指针类型的元素(int* arr和int* data),data = arr, 相当于把arr中存储的地址赋给了data。
//data和arr存储的值(地址)都相等,解引用是解引用他们存储的值,又因为*arr + 1 == arr[1] ,所以*data+1 == data[1],因为他们存储的值相同,所以他们指向的是同一块数组区域。
//所以data[1] == arr[1]
//data是一个指向数组的指针,为什么data[i]不用解引用直接使用
typedef struct SeqList {
//
SLDatatype* a;//开辟一个数组,这是指向动态开辟数组元素的指针。
int size;//当前存储元素的个数
int capacity;//容量--空间大小
}SL;
//初始化顺序表
void SLInit(SL* List);
void SLDestory(SL* ps);
//打印顺序表
void SLPrint(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);
-
SeqList.c 函数功能的实现
-
#define _CRT_SECURE_NO_WARNINGS 1 #include"SeqList.h" //顺序表初始化 void SLInit(SL* ps) { ps->a = NULL; ps->capacity = ps->size = 0; } //打印顺序表 void SLPrint(SL* ps) { //assert(ps != NULL); assert(ps); int i = 0; for ( i = 0; i < ps->size; i++) { printf("%d ", ps->a[i]); } } //销毁顺序表 void SLDestory(SL* ps) { if (ps->a) { free(ps->a); ps->a = NULL; ps->capacity = ps->size = 0; } } //判定容量 void CheckCapacity(SL* List) { if (List->capacity == List->size)//如果相等证明容量满了 { int newcapcity = List->capacity == 0 ? 4 : List->capacity * 2; SLDatatype* tmp = (SLDatatype*)realloc(List->a, newcapcity * sizeof(SL)); if (tmp == NULL) { perror("realloc fail"); exit(-1); } List->a = tmp; List->capacity = newcapcity; } } //顺序表尾插 void SLPushBack(SL* ps, SLDatatype x) { //插入函数复用 SLInsert(ps, ps->size, x); //CheckCapacity(ps); //ps->a[ps->size] = x; //ps->size++; } // 顺序表头插 void SLPushFront(SL* ps, SLDatatype x) { //插入函数复用 SLInsert(ps, 0, x); //CheckCapacity(ps); //int end = ps->size - 1; 挪动数据 //while (end >= 0) //{ // ps->a[end + 1] = ps->a[end]; // --end; //} //ps->a[0] = x; //ps->size++; } // 顺序表尾删 void SLPopBack(SL* ps) { //Erase复用 SLErase(ps, ps->size-1); //assert 暴力检查 直接提示错误 //assert(ps->size > 0); //ps->size--; } // 顺序表头删 void SLPopFront(SL* ps) { //Erase复用 SLErase(ps, 0); /*assert(ps->size > 0); int i = 0; for ( i = 0; i < ps->size-1; i++) { ps->a[i] = ps->a[i + 1]; } ps->size--;*/ } //顺序表任意位置插入 void SLInsert(SL* ps, int pos, SLDatatype x) { CheckCapacity(ps); assert(ps); assert(pos >= 0 && pos <= ps->size); 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; while (begin < ps->size - 1) { ps->a[begin] = ps->a[begin + 1]; begin++; } ps->size--; }
-
test.c 函数功能的测试
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
void test1()
{
SL sl;
SLInit(&sl);
SLPushBack(&sl, 1);
SLPushBack(&sl, 2);
SLPushBack(&sl, 4);
SLPushBack(&sl, 5);
SLPushBack(&sl, 6);
//SLPopBack(&sl);
//SLPopBack(&sl);
//SLPopBack(&sl);
//SLPopBack(&sl);
//SLPopBack(&sl);
//SLPopBack(&sl);
//
//SLPushBack(&sl, 1);
//SLPushBack(&sl, 2);
//SLPushBack(&sl, 4);
SLPrint(&sl);
SLDestory(&sl);
}
void test2()
{
SL sl;
SLInit(&sl);
SLPushBack(&sl, 1);
SLPushBack(&sl, 2);
SLPushBack(&sl, 4);
SLPushBack(&sl, 5);
SLPushFront(&sl, 6);
/*SLPopBack(&sl);
SLPopFront(&sl);*/
SLInsert(&sl, 0, 50);
SLPopBack(&sl);
SLPopBack(&sl);
SLPopBack(&sl);
SLPopBack(&sl);
SLPopBack(&sl);
//SLPopFront(&sl);
SLPrint(&sl);
}
int main()
{
//test1();
test2();
//系统对越界的检查,是设岗抽查,越界不一定会报错。
//int a[10];
//a[10] = 1;
//a[11] = 1;
//a[12] = 1;
return 0;
}
3. SLErase和SLInsert图解
因为顺序表中头插 头删 尾插 尾删的功能跟SLInsert 和 SLErase实现差不多,所以暂时目前只做出这两个函数功能的图解。