不定长顺序表:
它与定长数据表最大的区别就是它可以进行动态扩容,因此需要用malloc实现
不定长顺序表的结构体设计中,与定长顺序表不同的地方在于
首先将静态数组换成保存malloc返回值的指针,
其次要增加一个变量用来存储当前最大空间个数
如下图所示:
结构体设计如下:
typedef int ELEM_TYPE;
typedef struct Desqlist
{
ELEM_TYPE* elem; //指针,用来接收mallloc返回值
int length; //当前有效值个数(当前有多少个格子被占用)
int list_size; //当前总空间个数(当前一共有多少个格子)
} Dsqlist, *PDsqlist;
与定长顺序表相比,不定长顺序表增加了扩容、销毁函数
下面是扩容操作,顺序表存满时,用realloc进行扩容
void Inc(PDsqlist p)
{
ELEM_TYPE *tmp = (ELEM_TYPE*)realloc(p->elem, sizeof(ELEM_TYPE) * p->list_size);
assert(tmp != NULL);
if(tmp == NULL)
{
printf("内存扩容失败");
return;
}
else
{
p->elem = tmp;
}
p->list_size *= 2; //扩容之后总格子数变为原来的双倍
}
下面是销毁操作,主要是为了防止内存泄漏问题
//销毁
void Destroy(PDsqlist p)
{
assert(p != NULL);
if (p == NULL)
{
return;
}
free(p->elem);
}
下面展示所有源码
定义头文件Dsqlist.h
#pragma once
typedef int ELEM_TYPE;
#define MAX_SIZE 10
#define INIT_SIZE 10
//不定长顺序表的结构体设计
typedef struct Desqlist
{
ELEM_TYPE* elem; //指针,用来接收mallloc返回值
int length; //当前有效值个数(当前有多少个格子被占用)
int list_size; //当前总空间个数(当前一共有多少个格子)
} Dsqlist, *PDsqlist;
//不定长顺序表可以实现的操作函数
//增删改查
//初始化
void Init_Dsqlist(PDsqlist p);
//按位置插入
bool Insert_pos(PDsqlist p, int pos, int val);
//按位置删除
bool Del_pos(PDsqlist p, int pos);
//按值删除
bool Del_val(PDsqlist p, int val);
// 获取 其有效长度
bool Get_length(PDsqlist p);
//扩容 以2倍扩容
void Inc(PDsqlist p);
// 获取值所在下标 (如果数据重复,则返回第一次出现的位置)
int Search(PDsqlist p, int val);
//判空
bool Is_Empty(PDsqlist p);
//判满
bool Is_Full(PDsqlist p);
//清空
void Clear(PDsqlist p);
//销毁
void Destroy(PDsqlist p);
//打印
void Show(PDsqlist p);
在Dsqlist.cpp文件中对函数功能进行实现
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "Dsqlist.h"
//初始化
void Init_Dsqlist(PDsqlist p)
{
assert(p != NULL);
if (NULL == p)
{
return;
}
p->elem = (ELEM_TYPE*)malloc(INIT_SIZE * sizeof(ELEM_TYPE));
assert(p->elem != NULL);
if (p->elem == NULL)
{
return;
}
p->length = 0;
p->list_size = INIT_SIZE;
}
//按位置插入
bool Insert_pos(PDsqlist p, int pos, int val)
{
//判空
assert(p != NULL);
if (NULL == p)
{
return false;
}
//判断插入位置 是否合法
assert(pos > 0 && pos <= p->length); //插入的时候pos ==p->length 合法
//判满操作
if (Is_Full(p))
{
Inc(p);
}
// 首先挪动数据 让值空出来,再将值val放进去即可
//插入,挪动数据 从后往前挪
for (int i = p->length-1; i >= pos; i--)
{
p->elem[i + 1] = p->elem[i];
}
//此时,挪动数据完成 标志着挪动数据完成 现在只需要 将插入的值val放进去
p->elem[pos] = val;
//修改length
p->length++;
return true;
}
//按位置删除
bool Del_pos(PDsqlist p, int pos)
{
//判空 判断定长顺序表是否存在
assert(p != NULL);
if (NULL == p)
{
return false;
}
//判断删除位置 是否合法
assert(pos > 0 && pos < p->length);
//判空操作
if (Is_Empty(p))
return false;
// 首先删除数据 让值空出来,将删除位置后面的有效值一次向前挪动一位,将删除位置覆盖掉即可
//删除,向前覆盖数据,离待删除位置最近的元素先挪动
for (int i = pos + 1; i <= p->length - 1; i++)
{
p->elem[i-1] = p->elem[i];
}
//此时,删除数据完成 标志着数据向前覆盖完成
//修改length
p->length--;
return true;
}
//按值删除
bool Del_val(PDsqlist p, int val)
{
//assert
int index = Search(p, val);
if (index == -1)
return false;
return Del_pos(p, index);
}
// 获取 其有效长度
bool Get_length(PDsqlist p)
{
return p->length;
}
//扩容 以2倍扩容
void Inc(PDsqlist p)
{
ELEM_TYPE *tmp = (ELEM_TYPE*)realloc(p->elem, sizeof(ELEM_TYPE) * p->list_size);
assert(tmp != NULL);
if(tmp == NULL)
{
printf("内存扩容失败");
return;
}
else
{
p->elem = tmp;
}
p->list_size *= 2; //扩容之后总格子数变为原来的双倍
}
// 获取值所在下标 (如果数据重复,则返回第一次出现的位置)
int Search(PDsqlist p, int val)
{
//判空
assert(p != NULL);
for (int i = 0; i < p->length; i++)
{
if (p->elem[i] == val)
{
return i;
}
}
return -1;
}
//判空
bool Is_Empty(PDsqlist p)
{
return p->length == 0;
}
//判满
bool Is_Full(PDsqlist p)
{
return MAX_SIZE == p->length;
}
//清空
void Clear(PDsqlist p)
{
assert(p != NULL);
if(p == NULL)
{
return;
}
p->length = 0;
}
//销毁
void Destroy(PDsqlist p)
{
assert(p != NULL);
if (p == NULL)
{
return;
}
free(p->elem);
}
//打印
void Show(PDsqlist p)
{
assert(p != NULL);
if (p == NULL)
{
return;
}
for (int i = 0; i < p->length; i++)
{
printf("%d ", p->elem[i]);
}
printf("\n");
}