图说数据结构之线性表顺序存储

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

本人在学习数据结构过程中的一点心得,与大家共享。

数据结构学习中,听课能理解,一写代码就抓耳挠腮,烫嘴的山芋,感觉无从下口。有些事情一画图就明白,所以通过图形理解和记忆是比较便捷的一种方法。本章先从最简单的线性表顺序存储图说一下。

一、本质还是数据结构

万事开头难,编程的开头就是怎样定义线性表的头结构。看图:

头结构

头结构一般包括:

  • 容量capacity:线性表的容量,线性表能够存储多少数据,初始化时给出。类型:int。
  • 长度length:线性表中已存储了多少数据。类型:int。
  • 节点node:一定是一个指针类型,指向一个空间、一组数据。类型:?

关键是这个node应该是什么结构的指针?

二、结构的初始化

初始化后的结构应该是这样的:

初始化后的表结构

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

这个结构存储数据后的样子应该是这样的:

线性表顺序存储的样子

从上面两张图中分析可知:

  1. malloc出来的元素是指向实际数据的指针,因此node就是指向实际数据指针的指针,node定义为二级指针比较合理。
  2. 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类型也可以,但是函数中需要类型转换。

简单的示例代码见资源信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值