数据结构:可变数组->链表

变长数组(variable-length array), 简称 VLA
C语言中,直到C99标准出现之前,声明数组时在方括号内只能使用整数常量表达式。
而C99做了很大改进,允许数组的[ ]中的值是整形变量或是整形表达式。这就解释了下面的情况:
int n;
scanf ("%d", &n);
int array[n];
虽然n确实是需要运行时动态确定的变量,但是在C99中,以这种变量作为数组大小的形式已经是允许的了。
这样的数组就被称之为“变长数组”。
注意:变长数组是指用整型变量或表达式声明或定义的数组,而不是说数组的长度会随时变化,变长数组在其生存期内的长度同样是固定的。

可变数组(Resizeable Array)

数组的大小可“长大”,具体实现是在前期指定数组的大小,并在后期重新定义数组大小。使数组能在原大小的基础上“长大”,原来空间定义的数据不改变地拷贝到新定义的空间,并释放原空间,多出的未利用的空间即为新增空间。可变数组主要用于事先不明确所需数组的大小,需要在程序的中后段手工扩充的具体问题中。

为实现可变的功能必须满足以下条件:

1.可变大小

2.可得到数组的大小

3.可访问数组其中的单元

Interface(接口,封装一定功能的集合)

Array array_creat(int init_size);

void array_free(Array *a);

int array_size(const Array *a);

int *array_at(Array *a,int index);

void array_inflate(Array *a,int more_size);

需要建一个项目,包括array.h和array.c文件,具体步骤省略。

可变数组的缺陷:数组每次长大都需要申请新的内存空间,并需要拷贝原数组数据并释放它。

                                                1.拷贝的时间呈线性增加

                                                2.在内存受限的情况下(如单片机的内存空间),明明有足够的内存空间却不能再申请新的空间了。

//在一个大小为2n+Block_size的内存空间中,当前的数组空间大小是n,n-Block_size是之前数组现已被释放的空间,2Block_size是未利用的内存空间。

//对于下一个数组的创建所需空间是n+Block_size,n-Block_size和2Block_size都不够大,虽然他们相加正好是n+Block_size,但因为不连续所以不能创建。

对于第一个缺陷可以用memcpy函数来解决,

函数名: memcpy
功  能: 从源source中拷贝n个字节到目标destin中
用  法: void *memcpy(void *destin, void *source, unsigned n);
程序例:

#include <stdio.h>
#include <string.h>
int main(void)
{
   char src[] = "*****";
   char dest[] = "0123456709";
   char *ptr;
   printf("destination before memcpy: %s\n", dest);
   ptr = memcpy(dest, src, strlen(src)); //这里用一个变量ptr来测试memcpy是否正常复制成功
   if (ptr)
      printf("destination after memcpy:  %s\n", dest);
   else
      printf("memcpy failed\n");
   return 0;
}

链表(Linked list)

链表是一种物理存储单元上非连续、非顺序的存储结构
(相对于数组和可变数组而言,数组的存储方式是在开创的一片连续空间中存入数据,所以其物理存储单元是连续且顺序的)
 
数据元素的逻辑顺序是通过链表中的 指针 链接次序实现的。链表由一系列结点(链表中每一个元素)组成,结点可以在运行时动态生成。
每个结点包括两个部分:一 .存储数据元素 的数据域,
                                            二 .是存储下一个结点地址的 指针 域。
由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。

链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取

链表有很多种不同的类型:单向链表双向链表以及循环链表

链表的提出主要在于顺序存储中的插入和删除的时间复杂度是线性时间的,而链表的操作则可以是常数时间的复杂度。

 

OTHERS:

1、链接存储方法
链接方式存储的线性表简称为链表(Linked List)。
链表的具体存储表示为:
① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)
② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))
注意:链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。

2、链表的结点结构
┌——┬——┐
 | data | next  |
└——┴——┘
数据域---存放数据元素
指针域---存放下一个结点地址
注意:
①链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的。
②每个结点只有一个链域的链表称为单链表(Single Linked List)。

3、头指针head和终端结点指针域的表示
单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。
注意:链表由头指针唯一确定,单链表可以用头指针的名字来命名。
终端结点无后继,故终端结点的指针域为空,即NULL。

4、单链表的一般图示法
由于我们常常只注重结点间的逻辑顺序,不关心每个结点的实际位置,可以用箭头来表示链域中的指针

 

线性表

线性表是一种基本的顺序存储数据结构,线性表都是以队列字符串等特殊线性表的形式来使用的

在实现线性表数据元素的存储方面,一般可用顺序存储结构和链式存储结构两种方法。链式存储结构包含在线性链表中,另外栈、队列和串也是线性表的特殊情况,又称为受限的线性结构。

线性表中所有的元素所占的存储空间是连续的,线性表中常用的有链表和顺序表,顺序表所占的存储空间必须连续,链表没有这个要求,连续指的是存储空间的连续


从变长数组到链表,数据组织方式即数据结构的改变,逐步降低了存储数据的空间复杂度和时间复杂度。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值