本人在学习数据结构过程中的一点心得,与大家共享。
数据结构学习中,听课能理解,一写代码就抓耳挠腮,烫嘴的山芋,感觉无从下口。有些事情一画图就明白,所以通过图形理解和记忆是比较便捷的一种方法。本章先从最简单的线性表顺序存储图说一下。
一、本质还是数据结构
万事开头难,编程的开头就是怎样定义线性表的头结构。看图:

头结构一般包括:
- 容量capacity:线性表的容量,线性表能够存储多少数据,初始化时给出。类型:int。
- 长度length:线性表中已存储了多少数据。类型:int。
- 节点node:一定是一个指针类型,指向一个空间、一组数据。类型:?
关键是这个node应该是什么结构的指针?
二、结构的初始化
初始化后的结构应该是这样的:

malloc函数开辟一块空间,用来存储数据,而node指向这个空间。由于data的类型结构和大小都不是预知的,所以malloc出来的一个个元素必定也是一个指针,后续代码中指向实际的data。
这个结构存储数据后的样子应该是这样的:

从上面两张图中分析可知:
- malloc出来的元素是指向实际数据的指针,因此node就是指向实际数据指针的指针,node定义为二级指针比较合理。
- data类型不预知,那么malloc出来的指针可定义为void*,那么,node可以定义为void**。
由此可知,这个头结构为:
typedef struct __SEQLINKLIST__
{
int capacity;
int length;
void **node;
}Linklist;
线性表的初始化也就顺理成章了:
LinkList* SeqList_Create(int capacity)
{
Linklist *head = NULL;
head = malloc(sizeof(Linklist));
head->node = malloc(sizeof(void*)*capacity);
if(head->node == NULL)
{
//printf
//return NULL;
}
memset(head->node, 0, sizeof(void*)*capacity);
head->capacity = capacity;
head->length = 0;
return head;
}
三、套路—增删改查
按照数据库的套路,一套增删改查函数,搭架子,写代码。
LinkList* SeqList_Create(int capacity);
int SeqList_Capacity(LinkList* list);
int Seqlist_Length(LinkList* list);
int SeqList_Insert(LinkList* list, LinkListNode* node, int pos);
LinkListNode* SeqList_Get(LinkList* list, int pos);
LinkListNode* SeqList_Remove(LinkList* list, int pos);
int SeqList_Update(LinkList* list, LinkListNode* node, int pos);
四、进一步—封装
给用户看到的是头文件,头文件对用户透明。而线性表的数据结构不易放到头文件中,应该是在线性表的编译好的库文件中。因此,头文件中定义的head和node应该是void:
typedef void LinkList;
typedef void LinkListNode;
线性表函数库中,改个名字:
typedef struct __SEQLINKLIST__
{
int capacity;
int length;
void **node;
}TLinklist;
LinkList* SeqList_Create(int capacity)
{
TLinklist *head = NULL;
head = malloc(sizeof(Linklist));
head->node = malloc(sizeof(void*)*capacity);
if(head->node == NULL)
{
//printf
//return NULL;
}
memset(t->node, 0, sizeof(void*)*capacity);
head->capacity = capacity;
head->length = 0;
return t;
}
int SeqList_Insert(LinkList* list, LinkListNode* node, int pos)
{
int i = 0;
TLinklist *head = list;
if(head==NULL || node==NULL || pos<0 || pos>=head->capacity)
{
printf("SeqList_Insert error!\n");
return -1;
}
for(i=head->len;i>pos;i--)
{
head->node[i] = head->node[i-1];
}
head->node[i] = node;
head->len++;
return 0;
}
LinkListNode* SeqList_Get(LinkList* list, int pos)
{
int i = 0;
TLinklist *head = NULL;
head = list;
return (LinkListNode*)head->node[pos];
}
LinkListNode* SeqList_Remove(LinkList* list, int pos)
{
int i = 0;
TLinklist *head = list;
LinkListNode* node;
if(head==NULL || pos<0 || pos>=head->len)
{
printf("SeqList_Remove error!\n");
return NULL;
}
node =(LinkListNode*)head->node[pos];
for(i=pos;i<head->len-1;i++)
{
head->node[i] = head->node[i+1];
}
head->len--;
return node;
}
五、其他类型行不行?
指针类型的长度是固定的,32位系统下4个字节,64位系统下8个字节。
因此理论上,如果把malloc出来的元素定义为unsigned int类型也可以,但是函数中需要类型转换。
简单的示例代码见资源信息。

本文深入探讨线性表顺序存储的实现原理,讲解如何定义和初始化头结构,通过图形帮助理解,提供增删改查操作的具体代码示例,并讨论不同数据类型的应用可能性。
659

被折叠的 条评论
为什么被折叠?



