最近学习数据结构的线性表,主要是借助教材《数据结构》(C语言版)那本。在课堂上学习的时候没有认真听讲,唉,,,书上面的程序没有写过,知识了解大概,现在开始准备面试,数据结构是首先要拿下的基础知识,所以开始了数据结构的再学习,下面是线性表部分,下面还会有栈、队列、串、数组、树、图、排序、查找等等。程序不一定完全正确,都是用C语言实现的书上的例子,没有包括所有的线性表性质,但基本上实现了线性表基本操作(顺序和链式),欢迎大家提出宝贵意见。
下面附上练习源码(仅作参考)
1 /**
2 * 线性表的各种操作
3 * 对应《数据结构(C语言版)》的教材
4 * @author:zhaoyafei
5 * @aime:2015-6-16
6 */
7 //引入必要头文件
8 #include <stdio.h>
9 #include <stdlib.h>
10 //约定的宏定义
11 #define TRUE 1
12 #define FALSE 0
13 #define OK 1
14 #define ERROR 0
15 #define INFEASIBLE -1
16 #define OVERFLOW -2
17
18 //初始空间分配量
19 #define LIST_INIT_SIZE 100
20 //空间分配的增量
21 #define LISTINCREMENT 10
22 //Status是函数的类型,其值是函数结果的状态码
23 typedef int Status;
24 //数据元素约定为ElemType,可以自己定义
25 typedef int ElemType;
26
27 //线性表的顺序实现
28 typedef struct{
29 ElemType * elem; //存储空间的基地址
30 int lenght; //当前的长度
31 int listsize;//当前分配的存储容量
32 }SqList;
33
34 //线性表的链式实现
35 typedef struct LNode{
36 ElemType data; //存储数据
37 struct LNode * next; //递归定义,指向下一个元素
38 }LNode,*LinkList;//结构体类型指针
39
40 //双向链表的实现
41 typedef struct DuLNode{
42 ElemType data;
43 struct DuLNode *prior;
44 struct DuLNode *next;
45 }DulNode, *DuLinkList;
46
47 /*************************顺序实现***************************/
48 //构造空的线性表
49 Status InitList(SqList &L, int lenght){
50 if (lenght == 0) {
51 lenght = LIST_INIT_SIZE;
52 }
53 L.elem = (ElemType *)malloc(lenght * sizeof(ElemType));
54
55 if(!L.elem){
56 exit(OVERFLOW); //分配存储空间失败
57 }
58 L.lenght = 0; //初始空表长度为0
59 L.listsize = lenght ;//初始存储容量为100
60 return OK;
61 }
62
63 //在第i的位置插入元素e
64 Status ListInse_Sq(SqList &L, ElemType e, int i){
65 ElemType *p, *q;
66 if(i < 0 || i > L.lenght){
67 //i的值不合法
68 return ERROR;
69 }
70 if (L.lenght >= L.listsize) {
71 //空间不够,重新分配存储空间
72 ElemType *newbase = (ElemType *)realloc(L.elem ,(L.listsize + LISTINCREMENT)*sizeof(ElemType));
73 if(!newbase){
74 return OVERFLOW; //存储分配失败
75 }
76 L.elem = newbase; //记录新基值
77 L.listsize += LISTINCREMENT; //增加存储容量
78 }
79 q = &L.elem[i]; //得到元素插入的位置
80 for (p = &L.elem[L.lenght]; p >= q; --p) {
81 *p = *(p-1); //把插入位置元素之后的元素往后移动
82 }
83 *q = e; //插入新元素e
84 L.lenght +=1;
85 return OK;
86 }
87
88 //删除第i位置元素,并用e返回其值
89 Status ListDelete_sq(SqList &L, int i, ElemType &e){
90 int *p,*q;
91 if(i < 0 || i > L.lenght){
92 return ERROR; //i的值不合法
93 }
94 q = &L.elem[i]; //被删除元素的位置为i;
95 e = *q; //被删除元素的值赋值给e
96 //被删除元素后的元素左移
97 for (p = q; p< (L.elem + L.lenght); p++){
98 *p = *(p + 1);
99 }
100 --L.lenght;
101 return OK;
102 }
103
104 //得到第i个元素
105 Status GetElem(SqList &L, int i, ElemType &e){
106 ElemType *p;
107 p = L.elem;
108 int j = 1;
109 if(i < 1){
110 exit(OVERFLOW);//下表不合法
111 }
112 while(p && j < i){
113 p = &L.elem[j];
114 j++; //寻找第i个元素,同时检查p是否越界
115 }
116 if(!p || j > i){
117 return false;//下标越界
118 }
119 e = L.elem[j-1];
120 return OK;
121 }
122
123 //打印线性表
124 void PrintList(SqList L){
125 for(int i = 0; i < L.lenght; i++) {
126 printf("%d ", *(L.elem + i));
127 }
128 printf("\r\n");
129 }
130
131 //合并两个线性表
132 void Combine(SqList La, SqList Lb, SqList &Lc){
133 ElemType *pa, *pb, *pc;
134 Lc.listsize = La.lenght + Lb.lenght;
135 InitList(Lc, Lc.listsize); //初始化LC\pc = Lc.elem;
136 Lc.lenght = Lc.listsize;
137 pc = Lc.elem;
138 pa = La.elem;
139 pb = Lb.elem;
140 //还没有循环完
141 while (pa <= &La.elem[La.lenght -1] && pb <= &Lb.elem[Lb.lenght -1]){
142 if (*pa <= *pb){
143 *pc++ = *pa++;
144 }else{
145 *pc++ = *pb++;
146 }
147 }
148 //插入La的剩余元素
149 while(pa <= &La.elem[La.lenght -1]){
150 *pc++ = *pa++;
151 }
152 //插入Lb的剩余元素
153 while(pb <= &Lb.elem[Lb.lenght -1]){
154 *pc++ = *pb++;
155 }
156 }
157
158 //冒泡排序法,排序线性表
159 void Sort(SqList &L){
160 ElemType *pd1,*pd2,nums,length = L.lenght;
161 for(int num = 0; num < length - 1; num++){
162 for(int num1 = num + 1 ;num1 < length; num1++){
163 pd1 = &L.elem[num];
164 pd2 = &L.elem[num1];
165 if(*pd1 > *pd2){
166 nums = *pd1;
167 *pd1 = *pd2;
168 *pd2 = nums;
169 }
170 }
171 }
172 }
173
174 /*************************链式实现***************************/
175 //单链表初始化
176 Status InitList_L(LinkList &L){
177 L = (LinkList)malloc(sizeof(LNode));
178 if(!L){
179 exit(OVERFLOW); //分配存储空间失败
180 }
181 L->next = NULL; //初始的头结点为空
182 return OK;
183 }
184
185 //逆向建立单链表
186 Status CreateList_L(LinkList &L, int n){
187 L = (LinkList)malloc(sizeof(LNode));
188 if(!L){
189 exit(OVERFLOW); //分配存储空间失败
190 }
191 L->next = NULL; //初始的头结点为空
192 printf("请输入5个整数:\n");
193 for(int i = n; i > 0; --i){
194 LinkList p;
195 p = (LinkList)malloc(sizeof(LNode));
196 scanf("%d",&p->data);
197 p->next = L->next;
198 L->next = p;
199 }
200 return OK;
201 }
202
203 //在建立好的单链表中的第n个位置插入元素e
204 Status ListInsert_L(LinkList &o, int n, ElemType e){
205 LinkList L = o;
206 int j = 0;//记录插入点的位置
207 while(L && j < n - 1 && n > 0){
208 L = L->next;
209 j++;
210 }
211 if(L){//合法
212 LinkList p;
213 p = (LinkList)malloc(sizeof(LNode));
214 p->data = e;
215 p->next = L->next;
216 L->next = p;
217 return OK;
218 }
219 }
220
221 //在建立好的单链表中的第n个位置删除元素,并用e返回
222 Status ListDelete_L(LinkList &o, int n, ElemType e){
223 LinkList L = o;
224 int j = 0; //记录插入点的位置
225 while(L && j < n - 1 && n > 0){
226 L = L->next;
227 j++;
228 }
229 if(L && L->next){//合法
230 LinkList q;
231 q = L->next;
232 e = q->data;
233 L->next = q->next;
234 free(q);
235 return OK;
236 }
237 }
238
239 //合并链式线性表
240 void Combine_L(LinkList &La, LinkList &Lb,LinkList &Lc){
241 LinkList pa,pb,pc;
242 pa = La->next;
243 pb = Lb->next;
244 //Lc = La;//把La作为Lc的头结点
245 pc = Lc;
246 while(pa && pb){
247 if(pa->data <= pb->data){//判断两者得大小
248 pc->next = pa;
249 pa = pa->next; //pa指针下移
250 }else{
251 pc->next = pb;
252 pb = pb->next; //pb指针下移
253 }
254 pc = pc->next; //pc下移一位
255 }
256 pc->next = pa ? pa : pb;
257 free(La);
258 free(Lb);
259 }
260
261 //得到第i个元素
262 Status GetElem_L(LinkList &L, int i, ElemType &e){
263 LinkList p;
264 p = L;
265 int j = 0;
266 if(i < 1){
267 exit(OVERFLOW);//下表不合法
268 }
269 while(p && j < i){
270 p = p->next;//寻找第i个元素,同时检查p是否越界
271 j++;
272 }
273 if(!p || j > i){
274 return false;//下标越界
275 }
276 e = p->data;
277 return OK;
278 }
279
280 //冒泡排序法排序单链表
281 void Sort_L(LinkList &L){
282 LinkList p,q;
283 int num;
284 for(p = L; p != NULL; p = p->next){
285 for(q = p->next;q != NULL; q = q->next){
286 if(p->data > q->data){
287 num = p->data;
288 p->data = q->data;
289 q->data = num;
290 }
291 }
292 }
293 }
294
295 //打印链表节点信息
296 void PrintfList_L(LinkList L){
297 if(L){
298 do{
299 L = L->next;
300 printf("%d ",L->data);
301 }while(L->next);
302 }
303 printf("\n");
304 }
305
306 /***********************双向链表实现*************************/
307 //单链表初始化
308 Status InitList_Du(DuLinkList &L){
309 L = (DuLinkList)malloc(sizeof(DulNode));
310 if(!L){
311 exit(OVERFLOW); //分配存储空间失败
312 }
313 L->next = NULL; //初始的头结点为空
314 L->prior = NULL;
315 return OK;
316 }
317
318 //在双向链表中第n个位置插入元素e;
319 Status ListInsert_Dul(DuLinkList &P, int n, ElemType e){
320 DuLinkList L = P;
321 int j = 0;//记录插入点的位置
322 while(L && j < n - 1 && n > 0){
323 L = L->next;
324 j++;
325 }
326 if(L){//合法
327 DuLinkList c;
328 c = (DuLinkList)malloc(sizeof(DulNode));
330 c->data = e;
331 c->next = L->next;
332 L->next = c;
333 if(c->next){
334 c->next->prior = c;
335 }
336 c->prior = L;
337 return OK;
338 }
339 }
340
341 //在双向链表中第n个位置删除元素,并用e返回数据;
342 Status ListDelete_Dul(DuLinkList &P, int n, ElemType &e){
343 DuLinkList L = P;
344 int j = 0;//记录插入点的位置
345 while(L && j < n && n > 0){
346 L = L->next;
347 j++;
348 }
349 if(L){//合法
350 e = L->data;
351 L->prior->next = L->next;
352 L->next->prior = L->prior;
353 //free(L);
354 return OK;
355 }
356 }
357
358 //打印双向链表的数据
359 void PrintList_Du(DuLinkList L){
360 if(L){
361 do{
362 L = L->next;
363 printf("%d ",L->data);
364 }while(L->next);
365 }
366 printf("\n");
367 }
368
369 //主方法
370 void main(){
371 ElemType e,f;
372 int init,i,elem;
373 int TestData[8] = {9,1,8,5,7,2,1,3};
374 int TestDataTwo[5] = {8,3,2,6,1};
375
376 printf("*************线性表顺序实现*************\n");
377 SqList La,Lb,Lc;
378 init = InitList(La, LIST_INIT_SIZE);
379
380 for (i = 0; i < 8; i++) {//初始化La
381 ListInse_Sq(La, TestData[i], i);
382 }
383 printf("La:\n构造后的La:");
384 PrintList(La);
385
386 GetElem(La,3,e);//得到第3个元素
387 printf("得到La的第3个元素是:%d\n",e);
388
389 ListDelete_sq(La,3,e);//线性表的删除操作
390 printf("删除后的La:");
391 PrintList(La);
392
393 ListInse_Sq(La,e,3);//还原数据
394
395 Sort(La);//排序
396 printf("排序后的La:");
397 PrintList(La);
398
399 printf("Lb:\n构造后的Lb:");
400 InitList(Lb, LIST_INIT_SIZE);
401 for (i = 0; i < 5; i++) {
402 ListInse_Sq(Lb, TestDataTwo[i], i);
403 }
404 PrintList(Lb);
405
406 Sort(Lb);//排序Lb
407 printf("排序后的Lb:");
408 PrintList(Lb);
409
410 printf("合并La与Lb后的Lc:");//合并La,Lb
411 Combine(La, Lb, Lc);
412 PrintList(Lc);
413
414 printf("\n*************线性表链式实现*************\n");
415 LinkList LaL,LbL,LcL,LdL;
416 //CreateList_L(LbL,5)//逆序建立单链表
417 InitList_L(LaL);//初始化单链表
418 printf("LaL:\n构造后的LaL:");
419 for (i = 1; i <= 8; i++) {//初始化La
420 ListInsert_L(LaL, i, TestData[i-1]);
421 }
422
423 PrintfList_L(LaL);//打印单链表信息
424
425 GetElem_L(LaL,3,e);//得到第3个元素
426 printf("得到LaL的第3个元素是:%d\n",e);
427
428 ListInsert_L(LaL,3,10);//插入新元素
429 printf("插入后的LaL:");
430 PrintfList_L(LaL);
431
432 ListDelete_L(LaL,3,e);//删除添加的新元素
433 printf("删除后的LaL:");
434 PrintfList_L(LaL);
435
436 Sort_L(LaL);//排序
437 printf("排序后的LaL:");
438 PrintfList_L(LaL);
439
440 printf("LbL:\n构造后的LbL:");
441 InitList_L(LbL);//初始化单链表
442
443 for (i = 1; i < 6; i++) {
444 ListInsert_L(LbL, i, TestDataTwo[i-1]);
445 }
446 PrintfList_L(LbL);
447
448 printf("排序后的LbL:");
449 Sort_L(LbL);//排序
450 PrintfList_L(LbL);
451
452 printf("合并La与Lb后的Lc:");
453 InitList_L(LcL);//初始化单链表
454 Combine_L(LaL, LbL, LcL);
455 PrintfList_L(LcL);
456
457 printf("\n*************双向链表的实现*************\n");
458 DuLinkList DuLa;
459 //初始化双向链表
460 InitList_Du(DuLa);
461
462 for (i = 1; i < 9; i++) {
463 ListInsert_Dul(DuLa, i, TestData[i-1]);
464 }
465 printf("DuLa:\n构造后的DuLa:");
466 PrintList_Du(DuLa);
467 printf("添加新元素元素后的DuLa:");
468 ListInsert_Dul(DuLa, 3, 10); //在第三个位置添加元素10
469 PrintList_Du(DuLa);
470
471 printf("删除新添加元素后的DuLa:");
472 ListDelete_Dul(DuLa,3,e);//删除元素
473 PrintList_Du(DuLa);
474
475 }
运行结果:

需要补充一下知识点:C语言动态内存分配,C动态内存分配主要有这几个函数:malloc、free、calloc、realloc
size表示分配内存的大小,函数会从内存池里取一块连续的内存,返回指向内存起始位置的指针,这块内存进行初始化,需要手动初始化也可以通过calloc初始化。
注意:malloc分配的是连续的内存。可用内存小于请求,malloc向操作系统请求得到更多的内存,如果无法提供更多内存,则返回一个NULL指针。
L.elem = (ElemType *)malloc(lenght * sizeof(ElemType));
calloc:原型 void*calloc(unsigned n,unsigned size)
其中n表示需要分配内存的数据项个数,size指每个数据项的大小。malloc和calloc之间主要区别:calloc返回指向内存的指针之前把它初始化未0。 请求内存数量的方式不同。
realloc:原型:void *realloc(void*list,unsigned size)
将list所指的已分配内存区的大小改为size。realloc是修改一个原先已经分配的内存块的大小。如果原先的内存块无法改变大小,realloc将分配另一块正确大小的内存,并把原先那块内存的内容复制到新的快上。
例如:ElemType *newbase = (ElemType *)realloc(L.elem ,(L.listsize +LISTINCREMENT)*sizeof(ElemType));
C语言中,free可以释放calloc, malloc, realloc动态分配的空间,注意:释放的不是自己定义的指针,而是定义的指针指向的空间。自己定义的普通指针能不能可以通过free释放,这个要看情况。如果定义的指针指向动态分配的地址空间,则可以使用free释放指针指向的这段空间;否则,就不能使用free释放指针指向的空间。
来源:https://www.cnblogs.com/zyf-zhaoyafei/p/4580517.html