感觉不定长顺序表与定长的主要区别就是用指针存放元素,并用realloc()扩容。
不定长顺序表结构体的样子
elem用指针,length初始为0,用宏定义总长度,可以不大(节省空间),空间不够时扩容。
不定长顺序表主要操作(其实跟定长差不多):
再次强调elem是指针,不是数组了!!!
#define INIT_SIZE 10
typedef struct DSQList//不定长顺序表
{
int* elem;
int length;
int listsize;//总容量
}DSQList, * DPSQList;
void InitSqlist(DPSQList ps);//初始化的声明
bool Insert(DPSQList ps, int pos, int val);//插入数据,在ps顺序表的pos位置插入val
bool IsEmpty(DPSQList ps);//判断是否为空
int Search(DPSQList ps, int key);//查找,在ps查找第一个key值,返回下标,没有返回-1
bool DelPos(DPSQList ps, int pos);//删除,pos位置的值
bool DelVal(DPSQList ps, int val);//删除,第一个val值
int GetPrio(DPSQList ps, int key);//返回key的前驱下标,如果不存在返回-1
int GetNext(DPSQList ps, int key);//返回key的后继下标,如果不存在返回-1
void Show(DPSQList ps);//输出
void Destroy(DPSQList ps);//销毁内存
下面写几个与定长顺序表不同的部分
初始化:
注意是给ps->elem动态分配内存而非ps
void InitSqlist(DPSQList ps)//初始化的声明
{
assert(ps != NULL);
if (ps == NULL)
return;
ps->elem = (int*)malloc(sizeof(int)* INIT_SIZE);
ps->listsize = INIT_SIZE;
ps->length = 0;
}
扩容:
此操作在插入中
因为外部不需要知道这一步的存在(使用的时候只知道输入输出就好),所以这两个函数设为静态的:static bool
void *realloc(void *memblock,size_t size);
static bool IsFull(DPSQList ps)//static外部不引用(为内部服务)
{
return ps->length == ps->listsize;
}
static bool Inc(DPSQList ps)//扩容
{
ps->elem = (int*)realloc(ps->elem, sizeof(int) * ps->listsize * 2);//扩容用realloc
assert(ps->elem != NULL);
ps->listsize *= 2;//扩容到两倍
return true;
}
插入操作与定长相似,只是多一步调用上面两个函数,判断是否满了如果满了就扩容。
销毁:
void Destroy(DPSQList ps)//销毁
{
free(ps->elem);
ps->elem = NULL;//防止释放两次空间变成野指针
ps->length = 0;
ps->listsize = 0;
// ps = NULL;//无效代码
}
其余的操作与定长顺序表相同。
总结
顺序表的特点:
1.插入数据的时间复杂度是O(n)(需要移动大量元素),尾插O(1)
2.删除同上
3.通过下标访问数据的时间复杂度是O(1),随机访问,随机存取
4.存储密度大(对比链表)