线性表学习笔记

北城余情 提交于 2020-01-22 01:48:08

  最近学习数据结构的线性表,主要是借助教材《数据结构》(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

malloc:原型 void *malloc(unsigned size)

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));  
free():  原型:void free (void* list);
  C语言中,free可以释放calloc, malloc, realloc动态分配的空间,注意:释放的不是自己定义的指针,而是定义的指针指向的空间。自己定义的普通指针能不能可以通过free释放,这个要看情况。如果定义的指针指向动态分配的地址空间,则可以使用free释放指针指向的这段空间;否则,就不能使用free释放指针指向的空间。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!