线性结构——线性表

一、简介

  数据结构中的逻辑结构分为线性结构和非线性结构,简单地说,线性结构是n个数据元素的有序(次序)集合,它有下列几个特征:

  1)集合中必存在唯一的一个"第一个元素";

  2)集合中必存在唯一的一个"最后的元素";

  3)除最后元素之外,其它数据元素均有唯一的"后继";

  4)除第一元素之外,其它数据元素均有唯一的"前驱"。

  一个线性表可以表示成一个线性序列:k1,k2,…,kn,其中k1是开始结点,kn是终端结点。

  一般线性表包含下列基本操作:初始化、销毁、重置为空表、判断是否为空、获取长度、根据位置获取对应元素、查找元素、获取指定元素的前驱和后继元素、插入元素、删除元素、遍历元素。

二、线性表的顺序表示和实现

  线性表的顺序表示指的是用物理上的一段连续的地址来存储数据元素,如下图所示。如果第一个元素的在内存上的地址为a1,每个元素占用的空间是1,那么第n个元素的地址就是a1+(n-1) x 1。

         

  只要确定了第一个元素的地址,那么我们可以对线性表中的任一元素随机存取,由于编程语言中的数组也有随机存取的特点,下面就用数组来描述线性表的顺序存储结构。

三、代码实现

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 #define TRUE 1
  5 #define FALSE 0
  6 #define OK 1
  7 #define ERROR 0
  8 #define INIT_SIZE 10        //初始化表长
  9 #define INCREMENT_SIZE 5    //分配增量
 10 
 11 typedef int Status;
 12 typedef int Elemtype;
 13 
 14 /*
 15  * 存储结构
 16  */
 17 typedef struct
 18 {
 19     Elemtype *elem;    //存储空间基址
 20     int length;        //当前长度
 21     int size;        //当前分配的表长大小
 22 } SqList;
 23 
 24 /*
 25  * 初始化一个空的线性表
 26  */
 27 Status InitList(SqList *L)
 28 {
 29     L->elem = (Elemtype *) malloc(INIT_SIZE * sizeof(Elemtype));
 30     if (!L->elem)
 31     {
 32         return ERROR;
 33     }
 34     L->length = 0;
 35     L->size = INIT_SIZE;
 36     return OK;
 37 }
 38 
 39 /*
 40  * 销毁线性表
 41  */
 42 Status DestroyList(SqList *L)
 43 {
 44     free(L->elem);
 45     L->length = 0;
 46     L->size = 0;
 47     return OK;
 48 }
 49 
 50 /*
 51  * 清空线性表
 52  */
 53 Status ClearList(SqList *L)
 54 {
 55     L->length = 0;
 56     return OK;
 57 }
 58 
 59 /*
 60  * 判断线性表是否为空
 61  */
 62 Status isEmpty(const SqList L)
 63 {
 64     if (0 == L.length)
 65     {
 66         return TRUE;
 67     }
 68     else
 69     {
 70         return FALSE;
 71     }
 72 }
 73 
 74 /*
 75  * 获取长度
 76  */
 77 Status getLength(const SqList L)
 78 {
 79     return L.length;
 80 }
 81 
 82 /*
 83  * 根据位置获取元素
 84  */
 85 Status GetElem(const SqList L, int i, Elemtype *e)
 86 {
 87     if (i < 1 || i > L.length)
 88     {
 89         return ERROR;
 90     }
 91     *e = L.elem[i - 1];
 92     return OK;
 93 }
 94 
 95 /*
 96  * 比较两个元素是否相等
 97  */
 98 Status compare(Elemtype e1, Elemtype e2)
 99 {
100     if (e1 == e2)
101     {
102         return 0;
103     }
104     else if (e1 < e2)
105     {
106         return -1;
107     }
108     else
109     {
110         return 1;
111     }
112 }
113 
114 /*
115  * 查找元素
116  */
117 Status FindElem(const SqList L, Elemtype e, Status (*compare)(Elemtype, Elemtype))
118 {
119     int i;
120     for (i = 0; i < L.length; i++)
121     {
122         if (!(*compare)(L.elem[i], e))
123         {
124             return i + 1;
125         }
126     }
127     if (i >= L.length)
128     {
129         return ERROR;
130     }
131 }
132 
133 /*
134  * 查找前驱元素
135  */
136 Status PreElem(const SqList L, Elemtype cur_e, Elemtype *pre_e)
137 {
138     int i;
139     for (i = 0; i < L.length; i++)
140     {
141         if (cur_e == L.elem[i])
142         {
143             if (i != 0)
144             {
145                 *pre_e = L.elem[i - 1];
146             }
147             else
148             {
149                 return ERROR;
150             }
151         }
152     }
153     if (i >= L.length)
154     {
155         return ERROR;
156     }
157 }
158 
159 /*
160  * 查找后继元素
161  */
162 Status NextElem(const SqList L, Elemtype cur_e, Elemtype *next_e)
163 {
164     int i;
165     for (i = 0; i < L.length; i++)
166     {
167         if (cur_e == L.elem[i])
168         {
169             if (i < L.length - 1)
170             {
171                 *next_e = L.elem[i + 1];
172                 return OK;
173             }
174             else
175             {
176                 return ERROR;
177             }
178         }
179     }
180     if (i >= L.length)
181     {
182         return ERROR;
183     }
184 }
185 
186 /*
187  * 插入元素
188  */
189 Status InsertElem(SqList *L, int i, Elemtype e)
190 {
191     Elemtype *new;
192     if (i < 1 || i > L->length + 1)
193     {
194         return ERROR;
195     }
196     if (L->length >= L->size)
197     {
198         new = (Elemtype*) realloc(L->elem, (L->size + INCREMENT_SIZE) * sizeof(Elemtype));
199         if (!new)
200         {
201             return ERROR;
202         }
203         L->elem = new;
204         L->size += INCREMENT_SIZE;
205     }
206     Elemtype *p = &L->elem[i - 1];
207     Elemtype *q = &L->elem[L->length - 1];
208     for (; q >= p; q--)
209     {
210         *(q + 1) = *q;
211     }
212     *p = e;
213     ++L->length;
214     return OK;
215 }
216 
217 /*
218  * 删除元素并返回其值
219  */
220 Status DeleteElem(SqList *L, int i, Elemtype *e)
221 {
222     if (i < 1 || i > L->length)
223     {
224         return ERROR;
225     }
226     Elemtype *p = &L->elem[i - 1];
227     *e = *p;
228     for (; p < &L->elem[L->length]; p++)
229     {
230         *(p) = *(p + 1);
231     }
232     --L->length;
233     return OK;
234 }
235 
236 /*
237  * 访问元素
238  */
239 void visit(Elemtype e)
240 {
241     printf("%d ", e);
242 }
243 
244 /*
245  * 遍历线性表
246  */
247 Status TraverseList(const SqList L, void (*visit)(Elemtype))
248 {
249     int i;
250     for (i = 0; i < L.length; i++)
251     {
252         visit(L.elem[i]);
253     }
254     return OK;
255 }
256 
257 /*
258  * 主函数测试
259  */
260 int main()
261 {
262     SqList L;
263     if (InitList(&L))
264     {
265         Elemtype e;
266         printf("init_success\n");
267         int i;
268         for (i = 0; i < 10; i++)
269         {
270             InsertElem(&L, i + 1, i);
271         }
272         printf("length is %d\n", getLength(L));
273         if (GetElem(L, 1, &e)) {
274             printf("The first element is %d\n", e);
275         }
276         else
277         {
278             printf("element is not exist\n");
279         }
280         if (isEmpty(L))
281         {
282             printf("list is empty\n");
283         }
284         else
285         {
286             printf("list is not empty\n");
287         }
288         printf("The 5 at %d\n", FindElem(L, 5, *compare));
289         PreElem(L, 6, &e);
290         printf("The 6's previous element is %d\n", e);
291         NextElem(L, 6, &e);
292         printf("The 6's next element is %d\n", e);
293         DeleteElem(&L, 1, &e);
294         printf("delete first element is %d\n", e);
295         printf("list:");
296         TraverseList(L, visit);
297         if (DestroyList(&L))
298         {
299             printf("\ndestroy_success\n");
300         }
301     }
302     return 0;
303 }

四、线性表的链式表示和实现

  线性表的顺序存储结构是逻辑位置和物理位置都相邻,而链式存储结构是逻辑位置相邻,但物理位置不一定相邻,相比顺序存储结构,它不能随机存取,但在插入和删除操作时不需要移动元素,大大提高了增加和删除元素的效率。

  通常链式存储结构会有一个个结点组成,结点中包含两个域一个是数据域,一个是指针域,数据域中存储数据,指针域中存储下一个后继元素的地址,如下图所示,这一个个结点组成链表,也称线性链表或单链表。

      

  单链表的逻辑结构如下图所示     

  除了单链表之外还有循环链表和双向链表,循环链表的特点是最后一个结点的指针指向头结点,形成一个环,双向链表的特点是结点中多了一个指向前驱元素的指针,这两种链表的逻辑结构如下面两张图所示

循环链表

双向链表

单链表实现代码

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 #define TRUE 1
  5 #define FALSE 0
  6 #define OK 1
  7 #define ERROR 0
  8 #define OVERFLOW -2
  9 
 10 typedef int ElemType;
 11 typedef int Status;
 12 
 13 /*
 14  * 存储结构
 15  */
 16 typedef struct LNode
 17 {
 18     ElemType data;
 19     struct LNode *next;
 20 }LNode, *LinkList;
 21 
 22 /*
 23  * 初始化线性表
 24  */
 25 void InitList(LinkList *L)
 26 {
 27     *L = (LinkList) malloc(sizeof(LNode));
 28     if (!L)
 29     {
 30         exit(OVERFLOW);
 31     }
 32     (*L)->next = NULL;
 33 }
 34 
 35 /*
 36  * 销毁线性表
 37  */
 38 void DestroyList(LinkList *L)
 39 {
 40     LinkList temp;
 41     while (*L)
 42     {
 43         temp = (*L)->next;
 44         free(*L);
 45         *L = temp;
 46     }
 47 }
 48 
 49 /*
 50  * 清空线性表
 51  */
 52 void ClearList(LinkList L)
 53 {
 54     LinkList p = L->next;
 55     L->next = NULL;
 56     DestroyList(&p);
 57 }
 58 
 59 /*
 60  * 判断是否为空
 61  */
 62 Status isEmpty(LinkList L)
 63 {
 64     if (L->next)
 65     {
 66         return FALSE;
 67     }
 68     else
 69     {
 70         return TRUE;
 71     }
 72 }
 73 
 74 /*
 75  * 获取长度
 76  */
 77 int GetLength(LinkList L)
 78 {
 79     int i = 0;
 80     LinkList p = L->next;
 81     while (p)
 82     {
 83         i++;
 84         p = p->next;
 85     }
 86     return i;
 87 }
 88 
 89 /*
 90  * 根据位置获取元素
 91  */
 92 Status GetElem(LinkList L, int i, ElemType *e)
 93 {
 94     int j = 1;
 95     LinkList p = L->next;
 96     while (p && j < i)
 97     {
 98         j++;
 99         p = p->next;
100     }
101     if (!p || j > i)
102     {
103         return ERROR;
104     }
105     *e = p->data;
106     return OK;
107 }
108 
109 /*
110  * 比较两个元素是否相等
111  */
112 Status compare(ElemType e1, ElemType e2)
113 {
114     if (e1 == e2)
115     {
116         return 0;
117     }
118     else if (e1 < e2)
119     {
120         return -1;
121     }
122     else
123     {
124         return 1;
125     }
126 }
127 
128 /*
129  * 查找指定元素的位置
130  */
131 int FindElem(LinkList L, ElemType e, Status (*compare)(ElemType, ElemType))
132 {
133     int i = 0;
134     LinkList p = L->next;
135     while (p)
136     {
137         i++;
138         if (!compare(p->data, e))
139         {
140             return i;
141         }
142         p = p->next;
143     }
144     return 0;
145 }
146 
147 /*
148  * 获取前驱元素
149  */
150 Status PreElem(LinkList L, ElemType cur_e, ElemType *pre_e)
151 {
152     LinkList q, p = L->next;
153     while (p->next)
154     {
155         q = p->next;
156         if (q->data == cur_e)
157         {
158             *pre_e = p->data;
159             return OK;
160         }
161         p = q;
162     }
163     return ERROR;
164 }
165 
166 /*
167  * 获取后继元素
168  */
169 Status NextElem(LinkList L, ElemType cur_e, ElemType *next_e)
170 {
171     LinkList p = L->next;
172     while (p->next)
173     {
174         if (p->data == cur_e)
175         {
176             *next_e = p->next->data;
177             return OK;
178         }
179         p = p->next;
180     }
181     return ERROR;
182 }
183 
184 /*
185  * 插入元素
186  */
187 Status InsertElem(LinkList L, int i, ElemType e)
188 {
189     int j = 0;
190     LinkList s, p = L;
191     while (p && j < i - 1)
192     {
193         j++;
194         p = p->next;
195     }
196     if (!p || j > i - 1)
197     {
198         return ERROR;
199     }
200     s = (LinkList) malloc(sizeof(LNode));
201     s->data = e;
202     s->next = p->next;
203     p->next = s;
204     return OK;
205 }
206 
207 /*
208  * 删除元素并返回值
209  */
210 Status DeleteElem(LinkList L, int i, ElemType *e)
211 {
212     int j = 0;
213     LinkList q, p = L;
214     while (p->next && j < i - 1)
215     {
216         j++;
217         p = p->next;
218     }
219     if (!p->next || j > i - 1)
220     {
221         return ERROR;
222     }
223     q = p->next;
224     p->next = q->next;
225     *e = q->data;
226     free(q);
227     return OK;
228 }
229 
230 /*
231  * 访问元素
232  */
233 void visit(ElemType e)
234 {
235     printf("%d ", e);
236 }
237 
238 /*
239  * 遍历线性表
240  */
241 void TraverseList(LinkList L, void (*visit)(ElemType))
242 {
243     LinkList p = L->next;
244     while (p)
245     {
246         visit(p->data);
247         p = p->next;
248     }
249 }
250 
251 int main()
252 {
253     LinkList L;
254     InitList(&L);
255     ElemType e;
256     int i;
257     if (L)
258     {
259         printf("init success\n");
260     }
261 
262     if (isEmpty(L))
263     {
264         printf("list is empty\n");    
265     }
266 
267     for (i = 0; i < 10; i++)
268     {
269         InsertElem(L, i + 1, i);
270     }
271 
272     if (GetElem(L, 1, &e)) {
273         printf("The first element is %d\n", e);
274     }
275 
276     printf("length is %d\n", GetLength(L));
277 
278     printf("The 5 at %d\n", FindElem(L, 5, *compare));
279 
280     PreElem(L, 6, &e);
281     printf("The 6's previous element is %d\n", e);
282 
283     NextElem(L, 6, &e);
284     printf("The 6's next element is %d\n", e);
285 
286     DeleteElem(L, 1, &e);
287     printf("delete first element is %d\n", e);
288 
289     printf("list:");
290     TraverseList(L,visit);
291 
292     DestroyList(&L);
293     if (!L) {
294         printf("\ndestroy success\n");    
295     }
296 }

总结

  顺序存储结构中的元素在逻辑位置和物理位置上都相邻,链式存储结构中的元素在逻辑位置上相邻,但在物理位置上不一定相邻,顺序存储结构读取元素的效率比较高,链式存储结构添加和删除元素的效率比较高。链式存储结构除了单链表之外,还有循环链表和双向链表。

posted @ 2016-06-22 15:25  新生代黑马  阅读(557)  评论(0)    收藏  举报