线性表是一组 按线性顺序排列的、具有相同特征的数据元素的有限序列 ,其中的数据元素之间存在一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(这句话只适用大部分线性表,而不是全部,如循环链表把最后一个数据元素的尾指针指向了首位结点)。线性表可以用于表示一串有序的数据,例如数组、链表、栈和队列等都是线性表的实现方式。
线性表中的「单链表」的实现,包括单链表的顺序存储(数组实现)和单链表的链式存储。这篇文章主要介绍单链表的顺序存储(数组实现)。
数组和链表的特点
首先介绍一下数组和链表的特点。
数组:创建数组时会在内存空间中划分出一块连续的内存,然后数据进入时会将数据按顺序存储在这块连续的内存中。因为数组在存储数据时是按顺序存储的,存储数据的内存也是连续的。所以,数组的特点就是寻址读取数据容易,插入和删除比较困难 / 费时 。
链表:链表不同于数组,不会先划分出一块连续的内存,链表中的数据并不是连续的,链表在存储数据的内存中有两块区域,一块区域用来存储数据,一块区域用来记录下一个数据保存在哪里。虽然链表是线性表,但是并不会按线性的顺序存储数据。所以,链表在插入和删除时比较容易,在读取数据时比较麻烦 。
这里的容易,即意味着时间复杂度低;麻烦,即意味着时间复杂度高。
链表的顺序存储(数组实现)
链表的 API 主要包括:
创建并初始化链表
查找链表中的元素
向链表中插入元素
删除链表中的元素
获取链表的长度
链表结构定义
1 2 3 4 5 6 7 #define MAX_SIZE (100) typedef struct { int data[MAX_SIZE]; int length; } ArrayList;
这段代码定义了一个名为 ArrayList
的结构体,用来表示一个数组实现的链表。
该结构体包含两个成员变量:
int data[MAX_SIZE]
:一个整型数组,用来存储链表中的元素。
int length
:一个整型变量,表示链表的长度。
通过使用这个结构体,我们可以创建一个顺序存储结构的链表,其中元素按照顺序存储在数组中,并且可以通过索引来访问和修改链表中的元素。
创建并初始化链表
使用动态申请内存空间的方式创建并初始化一个链表。
1 2 3 4 5 6 7 ArrayList *initArrayList () { ArrayList *list = (ArrayList *)malloc (sizeof (ArrayList)); memset (list ->data, 0 , MAX_SIZE * sizeof (int )); list ->length = 0 ; return list ; }
查找链表中的元素
在链表中查找目标元素第一次出现时的索引,不存在则返回 -1。
1 2 3 4 5 6 7 8 9 int findArrayList (ArrayList *list , int target) { for (int i = 0 ; i < list ->length; i++) { if (list ->data[i] == target) { return i; } } return -1 ; }
为什么查找成功的平均比较次数为 n + 1 2 \frac {n+1}{2} 2 n + 1 呢?
假设链表的长度为 n n n ,若元素在链表中存在,在最坏情况下,需要比较 n n n 次才能找到元素;在最好情况下,只需要比较 1 1 1 次就能找到元素。因此,平均比较次数为 n + 1 2 \frac {n+1}{2} 2 n + 1 。
向链表中插入元素
向链表中指定的索引位置插入一个元素,可以在有效数据的最前面和最后面插入元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int insertArrayList (ArrayList *list , int index, int element) { if (list ->length == MAX_SIZE) { printf ("List is full! Unable to insert element.\n" ); return -1 ; } else if (index < 0 || index > list ->length) { printf ("Invalid index! Unable to insert element.\n" ); return -1 ; } for (int i = list ->length - 1 ; i >= index; i--) { list ->data[i + 1 ] = list ->data[i]; } list ->data[index] = element; list ->length++; return 0 ; }
删除链表中的元素
删除链表中指定索引位置的元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int deleteArrayList (ArrayList *list , int index) { if (list ->length == 0 ) { printf ("List is empty! Unable to delete element.\n" ); return -1 ; } else if (index < 0 || index >= list ->length) { printf ("Invalid index! Unable to delete element.\n" ); return -1 ; } for (int i = index; i < list ->length - 1 ; i++) { list ->data[i] = list ->data[i + 1 ]; } list ->length--; return 0 ; }
获取链表的长度
获取链表中有效数据元素的长度。
1 2 3 int getArrayListLength (ArrayList *list ) { return list ->length; }
释放链表空间
1 2 3 void freeArrayList (ArrayList *list ) { free (list ); }
链表的数组实现完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_SIZE (100) typedef struct { int data[MAX_SIZE]; int length; } ArrayList; ArrayList *initArrayList () { ArrayList *list = (ArrayList *)malloc (sizeof (ArrayList)); memset (list ->data, 0 , MAX_SIZE * sizeof (int )); list ->length = 0 ; printf ("ArrayList size is %d bytes, data size is %d bytes.\n" , sizeof (list ), sizeof (list ->data)); return list ; } int findArrayList (ArrayList *list , int target) { for (int i = 0 ; i < list ->length; i++) { if (list ->data[i] == target) { return i; } } return -1 ; } int insertArrayList (ArrayList *list , int index, int element) { if (list ->length == MAX_SIZE) { printf ("List is full! Unable to insert element.\n" ); return -1 ; } else if (index < 0 || index > list ->length) { printf ("Invalid index! Unable to insert element.\n" ); return -1 ; } for (int i = list ->length - 1 ; i >= index; i--) { list ->data[i + 1 ] = list ->data[i]; } list ->data[index] = element; list ->length++; return 0 ; } int deleteArrayList (ArrayList *list , int index) { if (list ->length == 0 ) { printf ("List is empty! Unable to delete element.\n" ); return -1 ; } else if (index < 0 || index >= list ->length) { printf ("Invalid index! Unable to delete element.\n" ); return -1 ; } for (int i = index; i < list ->length - 1 ; i++) { list ->data[i] = list ->data[i + 1 ]; } list ->length--; return 0 ; } int getArrayListLength (ArrayList *list ) { return list ->length; } void printArrayList (ArrayList *list ) { for (int i = 0 ; i < list ->length; i++) { printf ("%d " , list ->data[i]); } printf ("\n" ); } void freeArrayList (ArrayList *list ) { free (list ); } int main () { ArrayList *list = initArrayList(); insertArrayList(list , 0 , 10 ); insertArrayList(list , 1 , 20 ); insertArrayList(list , 2 , 30 ); printArrayList(list ); insertArrayList(list , 2 , 40 ); insertArrayList(list , 0 , 15 ); printArrayList(list ); printf ("Length of list: %d\n" , getArrayListLength(list )); int index = findArrayList(list , 20 ); if (index != -1 ) { printf ("Element 20 is found at index %d\n" , index); } else { printf ("Element 20 is not found\n" ); } deleteArrayList(list , 1 ); printArrayList(list ); printf ("Length of list: %d\n" , getArrayListLength(list )); freeArrayList(list ); return 0 ; }
程序的输出结果为:
1 2 3 4 5 6 7 ArrayList size is 8 bytes, data size is 400 bytes. 10 20 30 15 10 20 40 30 Length of list: 5 Element 20 is found at index 2 15 20 40 30 Length of list: 4