顺序表
优点:
- 功能上类似于数组操作简单
- 能够实现随机访问,进行查询和修改效率高
缺点:
- 存储数据有上限
- 对于插入和删除效率低,因为需要移动大量元素
- 空间利用率低
结构体创建
typedef struct
{
char name[20];
short age;
char sex;
} Stu_t;
typedef struct
{
unsigned index;
Stu_t list[50];
} Sqlist_t;
创建顺序表
sqlist_t *create_list(void)
{
//申请表空间
Sqlist_t *L = malloc(sizeof(sqlist_t));
if(NULL == L)
{
printf("malloc memory failed!\n");
return NULL;
}
//初始化表空间
memset(L, 0, sizeof(Sqlist_t));
L->index = 0;
//返回表空间首地址
return L;
}
在顺序表中任意位置插入数据
/*
功能:在顺序表的任意位置插入数据
参数:L 顺序表首地址
pos 要插入的位置(unsigned int)
value 要插入的数据
返回值: 成功返回 0
失败返回-1
*/
int insert_data(Sqlist_t *L, int pos, Stu_t value)
{
//健壮性判断
if(NULL == L)
{
printf("Malloc memory failed!\n");
return -1;
}
//pos传入位置判断
if(pos > L->index || pos < 0)
{
printf("Pos error!\n");
return -1;
}
//表内空间判断
if(NULL == L->index)
{
printf("List is max!\n");
return -1;
}
//插入操作
Sqlist_t *S = L;//用一个新的指针变量来操作,避免误操作
int i = 0;
for(i = S->index; i > pos; i--)
{
S->list[i] = S->list[i - 1];
}
S->list[pos] = value;
//更新表记录标识
S->index++;
}
插入数据算法思路
- 在向顺序表中插入数据时,要考虑表参数的合法性,位置参数的合法性,和表的使用状况
- 表参数的合法性判断比较简单(不为NULL)
- 位置参数合法性判断为 位置参数不可以小于0且不能大于index
- 判断表参数合法性主要是为了维护表的逻辑结构
- 表的使用情况,表满不可再进行数据插入操作
- 当使用者传输的所有参数(表的首地址、位置)都合法的情况下且表未满才可以进行插入操作
- 先移动传入位置值到index标识范围内的数据(向后移动),主要目的是不破坏原有数据,否则将失去表的意义,移动算法如下:
1 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 |
pos | index |
value = 2;
index = 6;
pos = 1;
for(i = index; i > pos; i--)
{
i = i -1;
}
1 | value | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 |
-
用i变量定位到表使用标识的位置
i = index
-
移动结束条件为i移动到传入的位置
for(i = index; i > pos; i--)
-
然后将i前一个位置( i - 1 )的数据向后移动一个位置( i )
i = i - 1
-
循环结束时pos到index位置的数据整体向后移动了一个位置(此时pos位置上的数据与pos + 1的数据一致)
3.将数据整体移动后在进行数据插入(插入到pos对应的位置上即可)
S->list[pos] = value;
遍历顺序表
int show_list(Sqlist_t *L)
{
//健壮性判断
if(NULL == L)
{
printf("malloc memory failed!\n");
return -1;
}
if(NULL == L->index)
{
printf("list is NULL!\n");
return -1;
}
int i = 0;
for(i = 0; i < L->index; i++)
{
printf("name:%s, age:%hd, sex:%c\n", L->list[i].name, L->list[i].age, L->list[i].sex);
}
}
释放表空间
int free_list(Sqlist_t **L)
{
//健壮性判断
if(NULL == *L || NULL == L)
{
prinrf("传入的表参数非法\n");
return -1;
}
free(*L);
*L = NULL;
return 0;
}
删除表中任意位置数据
int delete_data(Sqlist_t *L, int pos)
{
//健壮性判断
if(NULL == L)
{
printf("传入的表参数非法\n");
return -1;
}
if(pos < 0 || pos >= L->index)
{
printf("传入位置非法\n");
return -1;
}
if(0 == L->index)
{
printf("表为空表,无数据可删\n");
return -1;
}
//删除对应位置参数
int i = 0;
//将pos位置后的数据整体向前移动一个位置,覆盖pos当前位置的数据,以达到删除的效果
for(i = pos; i < L->index - 1; i++)
{
L->list[i] = L->list[i + 1];
}
//更新表记录
L->index--;
return 0;
}
判断表是否为空
int empty_list(Sqlist_t *L)
{
if(NULL == L)
{
printf("传入的表参数非法\n");
return -1;
}
return 0 == L->index ? 0 : -1;
}
判断表是否为满
int empty_list(Sqlist_t *L)
{
if(NULL == L)
{
printf("传入的表参数非法\n");
return -1;
}
return N == L->index ? 0 : -1;
}
根据学生姓名去重
int Remove_Dup(Sqlist_t *L)
{
if(NULL == L)
{
printf("传入的表参数非法\n");
return -1;
}
if(0 == empty_list(L) || 1 == L->index)
{
printf("表为空表 或 只有一个元素无需去重\n");
return -1;
}
int i,j;
for(i = 0; i < L->index - 1; i++)
{
for(j = i + 1; j < L->index; j++)
{
if(0 == strcmp(L->list[i].name,L->list[j].name))
{
delete_data(L,j);
j--;//--是因为删除数据后,数据前移原本j位置的数据会被跳过
}
}
}
}
根据学生年龄排序
int sort_age(Sqlist_t *L)
{
if(NULL == L)
{
printf("传入的表参数非法\n");
return -1;
}
if(0 == empty_list(L) || 1 == L->index)
{
printf("表为空表 或 只有一个元素无需排序\n");
return -1;
}
int i, j;
Stu_t temp;
memset(&temp, 0, sizeof(temp));
for(i = 0; i < L->index; i++)
{
for(j = i + 1; j < L->index; j++)
{
if(L->list[i].age > L->list[j].age)
{
temp = L->list[i];
L->list[i] = L->list[j];
L->list[j] = temp;
}
}
}
}