数据结构之线性表的顺序存储结构实现
1 定义
- 线性表(List,链表):零个或多个数据元素的有限序列
元素之间是有顺序的,若存在多个元素,则第一个元素无前驱,最后一个元素无后继,其他每个元素都有且只有一个前驱和后继。 - 线性表的顺序存储是指在内存中用地址连续的一块存储空间顺序存放线性表的各元素。可以使用一维数组来实现顺序存储结构。
2 数据结构及操作
2.1 数据结构
typedef struct _tag_SeqList
{
int capacity;
int length;
unsigned int * node;
}TSeqList;
这里使用 typedef void SeqListNode 即:void 类型作为数据节点,可以存储任意类型的数据元素。
顺序存储的三个属性:
- 存储空间:node
- 链表的最大容量:capacity
- 链表的当前长度:length
2.2 操作
/*
* seqList.h
*/
#ifndef __MY_SEQLIST_H
#define __MY_SEQLIST_H
typedef void SeqList;
typedef void SeqListNode;
SeqList* SeqList_Create(int capacity);
void SeqList_Destroy(SeqList* list);
void SeqList_Claer(SeqList* list);
int SeqList_length(SeqList* list);
int SeqList_Capacity(SeqList* list);
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos);
SeqListNode* SeqList_Get(SeqList* list, int pos);
SeqListNode* SeqList_Delete(SeqList* list, int pos);
#endif // __MY_SEQLIST_H
3 主要操作实现
3.1 创建一个新链表
SeqList* SeqList_Create(int capacity)
{
int ret = 0;
TSeqList* tmp = NULL;
tmp = (TSeqList *)malloc(sizeof(TSeqList));
if(tmp == NULL)
{
ret = -1;
printf("func SeqList_Create() err: %d\n", ret);
return NULL;
}
tmp->node = (unsigned int *)malloc(sizeof(unsigned int *) * capacity);
if(tmp->node == NULL)
{
ret = -2;
printf("func SeqList_Create malloc err: %d\n", ret);
return NULL;
}
tmp->length = 0;
tmp->capacity = capacity;
return tmp;
}
3.2 销毁
//销毁链表
void SeqList_Destroy(SeqList* list)
{
TSeqList * tlist = NULL;
if(list == NULL)
{
return;
}
tlist = (TSeqList *)list;
if(tlist->node != NULL)
{
free(tlist->node);
}
free(tlist);
return;
}
3.3 插入操作
在链表 list 的第 pos 位置,插入元素node。
操作:
1)判断list,node,pos的合法性。
2)如果链表已满,返回。
3)从最后一个元素开始向前遍历到第pos个位置,分别将他们都向后移动一个位置。
4)将要插入元素填入位置pos处。
5)表长加1。
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos)
{
int ret = 0, i = 0;
TSeqList *tlist = NULL;
if(list == NULL || node == NULL || pos < 0)
{
ret = -1;
printf("func SeqList_Insert err:%d\n", ret);
return -1;
}
tlist = (TSeqList *)list;
//链表已满
if(tlist->length == tlist->capacity)
{
ret = -2;
printf("func SeqList_Insert err:%d\n", ret);
return -1;
}
//容错修正 如果链表已有6个元素, 容量为20, 用户在pos=10处插入
if(pos > tlist->length)
{
pos = tlist->length;
}
for(i = tlist->length; i > pos; i--)
{
tlist->node[i] = tlist->node[i - 1];
}
tlist->node[pos] = node;
tlist->length++;
return 0;
}
3.4 获取元素操作
注意:下标从0开始计算,即第一个元素在第0个位置。
SeqListNode* SeqList_Get(SeqList* list, int pos)
{
int ret = 0;
TSeqList *tlist = NULL;
if(list == NULL || pos < 0)
{
ret = -1;
printf("func SeqList_Get err:%d\n", ret);
return NULL;
}
tlist = (TSeqList *)list;
return tlist->node[pos];
}
3.5 删除操作
删除链表list第pos个位置的元素,并返回其元素。
操作:
1)判断合法性。
2)取出元素。
3)从第pos个位置开始遍历到最后一个元素位置,并分别将它们都向前移动一个位置。
4)表长减1.
SeqListNode* SeqList_Delete(SeqList* list, int pos)
{
int ret = 0, i = 0;
TSeqList *tlist = NULL;
if(list == NULL || pos < 0)
{
ret = -1;
printf("func SeqList_Delete err:%d\n", ret);
return NULL;
}
tlist = (TSeqList *)list;
SeqListNode *tmp = (SeqListNode *)tlist->node[pos];
for(i = pos+1; i < tlist->length; i++)
{
tlist->node[i-1] = tlist->node[i];
}
tlist->length--;
return tmp;
}
3.6 测试
/*
* seqlistTest.cpp
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "seqList.h"
typedef struct _Teacher
{
int age;
char name[64];
}Teacher;
int main()
{
int ret = 0, i = 0;
Teacher t1, t2, t3, t4, t5;
t1.age = 31;
t2.age = 32;
t3.age = 33;
t4.age = 34;
t5.age = 35;
SeqList* list = SeqList_Create(10);
if(list == NULL)
{
printf("func SeqLisat_Create() ret :%d\n", ret);
return;
}
//插入节点
ret = SeqList_Insert(list, (SeqListNode*)&t1, 0); //头插法
ret = SeqList_Insert(list, (SeqListNode*)&t2, 0);
ret = SeqList_Insert(list, (SeqListNode*)&t3, 0);
ret = SeqList_Insert(list, (SeqListNode*)&t4, 0);
ret = SeqList_Insert(list, (SeqListNode*)&t5, 0);
//遍历
for(i = 0; i < SeqList_length(list); i++)
{
Teacher* tmp = SeqList_Get(list, i);
printf("tmp->age:%d ", tmp->age);
}
//删除节点
while(SeqList_length(list) > 0)
{
SeqList_Delete(list, 0);
}
system("pause");
return 0;
}
3.7 线性表顺序存储的优缺点
优点:
- 无须为表示表中元素之间的逻辑关系额增加额外的存储空间。
- 可以快速地存取表中任一位置的元素
缺点:
- 插入和删除操作需要移动大量元素
- 当线性表长度变化较大时,难以确定存储空间的容量
- 造成存储空间的碎片