线性表的链式表示和实现----线性(单)链表
Posted 烽火前秦路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性表的链式表示和实现----线性(单)链表相关的知识,希望对你有一定的参考价值。
头文件 head.h
#include<string.h> #include<ctype.h> #include<malloc.h> /* malloc()等 */ #include<limits.h> /* INT_MAX等 */ #include<stdio.h> /* EOF(=^Z或F6),NULL */ #include<stdlib.h> /* atoi() */ #include<io.h> /* eof() */ #include<math.h> /* floor(),ceil(),abs() */ #include<process.h> /* exit() */ /* 函数结果状态代码 */ #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 /* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */ typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */ typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */ typedef int ElemType; //通过定义不同的类型来定义不同的存储类型 typedef struct LNode{ ElemType data; struct LNode *next; }LNode, *LinkList; //typedef struct LNode *LinkList; Status InitList_L(LinkList *L); Status DestoryList_L(LinkList *L); Status ClearList_L(LinkList *L); Boolean ListEmpty_L(LinkList L); int ListLength_L(LinkList L); Status GetElem_L(LinkList L, int i, ElemType *e); int LocateElem_L(LinkList L, ElemType e); Status PriorElem_L(LinkList L, ElemType cur_e, ElemType *pre_e); Status NextElem_L(LinkList L, ElemType cur_e, ElemType *next_e); Status ListInsert_L(LinkList *L, int i, ElemType e); Status ListDelet_L(LinkList *L, int i, ElemType *e); Status ListTraverse_L(LinkList L); void CreateList_R_L(LinkList *L, int n); void CreateList_F_L(LinkList *L, int n); void MergerList_L_L(LinkList A, LinkList B, LinkList *C); void MergerList_H_L(LinkList A, LinkList *B, LinkList *C);
算法实现
#include"head.h" //带有头结点的单链表 Status InitList_L(LinkList *L) { //操作结果:构造一个空线性表L *L = (LinkList)malloc(sizeof(LNode)); if (!(*L)) { printf("构造线性表失败!\n"); exit(OVERFLOW); } (*L)->next = NULL; return OK; } Status DestoryList_L(LinkList *L) { //初始条件:线性表L已存在,将其中的每一个指向后继元素的指针都free掉 //操作结果:销毁线性表L LinkList p; while (*L) { p = (*L)->next; free(*L);//头结点也要释放掉 *L = p; } return OK; } Status ClearList_L(LinkList *L) { //初始条件:线性表L已存在 //操作结果:将L重置为空表,不改变L,即只需将该链表中的指针全部释放掉但还保留其中的形式 //注意和DestoryList做对比 LinkList p, q; p = (*L)->next; //p指向第一个结点 while (p) //要保存大致结构 { q = p->next; free(p); p = q; } (*L)->next = NULL; return OK; } Boolean ListEmpty_L(LinkList L) { //初始条件:线性表L已存在 //操作结果:若L为空,则返回TRUE;否则,返回FASLE if (L->next) return FALSE; else return TRUE; } int ListLength_L(LinkList L) { //初始条件:线性表L已存在 //操作结果:返回L中数据元素个数 int i = 0; LinkList p = L->next; //单链表的第一个数据结点 while (p) { i++; p = p->next; } return i; } Status GetElem_L(LinkList L, int i, ElemType *e) { //初始条件:线性表L已存在且1<= i <= ListLength(L) ,L为带头结点的单链表头指针 //操作结果:用e返回L中第i个数据元素的值 LinkList p = L->next; int n = 1; while (p && n < i) //找到第i个元素 { p = p->next; n++; } if (!p || n > i) //寻找失败则退出该函数 return ERROR; *e = p->data; return OK; } int LocateElem_L(LinkList L, ElemType e) { //初始条件:线性表L已存在 //操作结果:返回L中第一个与元素e相等的数据元素的位序,若这样的元素不存在则返回0 int n = 0; LinkList p = L->next; //第一个结点,非头结点 while (p) { n++; if (p->data == e) return n; p = p->next; } return 0; } Status PriorElem_L(LinkList L, ElemType cur_e, ElemType *pre_e) { //初始条件:线性表L已存在 //操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则失败,pre_e无定义 LinkList p = L->next; //代表当前元素的前驱 LinkList q = p->next; //代表当前元素 while (q) //从第二个元素开始 { if (q->data == cur_e) { *pre_e = p->data; return TRUE; } p = q; q = q->next; } return INFEASIBLE; } Status NextElem_L(LinkList L, ElemType cur_e, ElemType *next_e) { //初始条件:线性表L已存在 //操作结果:若cur_e是L的数据元素且不是最后一个,则用pre_e返回它的后继,否则操作失败,next_e无意义 LinkList p = L->next; while (p) { if (p->data == cur_e) { p = p->next; if (p) { *next_e = p->data; return TRUE; } else return INFEASIBLE; } p = p->next; } return INFEASIBLE; } Status ListInsert_L(LinkList *L, int i, ElemType e) { //初始条件:线性表L已存在, 1<= i <=ListLength(L)+1 //操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 LinkList p = *L; int n = 1; LinkList t; if (i<1 || i>ListLength_L(*L) + 1) return ERROR; while (p && n<i)//找到位序i之前的结点,即i-1的结点 { p = p->next; n++; } if (!p || n > i) return FALSE; t = (LinkList)malloc(sizeof(struct LNode)); t->data = e; t->next = p->next; p->next = t; return OK; } Status ListDelet_L(LinkList *L, int i, ElemType *e) { //初始条件:线性表L已存在 //操作结果:在头结点的单链表L中,删除第i个元素,并有e返回其值 LinkList p = *L, q; int n = 1; if (i<1 || i>ListLength_L(*L) + 1) return ERROR; while (p->next && n < i) //寻找第i个结点,并令p指向其前驱 { p = p->next; n++; } if (!(p->next) || n > i) return FALSE; q = p->next; p->next = q->next; *e = q->data; free(q); return OK; } Status ListTraverse_L(LinkList L) { //初始条件:线性表L已存在 //操作结果:输出线性链表中的元素 LinkList p = L->next; while (p) { printf("%d ", p->data); p = p->next; } printf("\n"); return OK; } //算法2.11 从表尾到表头逆向建立单链表的算法 void CreateList_R_L(LinkList *L, int n) { LinkList p; *L = (LinkList)malloc(sizeof(LNode)); (*L)->next = NULL; printf("请输%d个元素值【空格键隔开】:", n); for (; n >= 1; n--) { p = (LinkList)malloc(sizeof(LNode)); scanf_s("%d", &p->data); p->next = (*L)->next; //插入到表头 (*L)->next = p; } } //算法2.11-1 从表头到表尾正向建立单链表的算法 void CreateList_F_L(LinkList *L, int n) { LinkList p, q; (*L) = (LinkList)malloc(sizeof(struct LNode)); (*L)->next = NULL; q = (*L);//q指向空表的头结点(相当于尾结点) printf("请输入%d个数据【空格键隔开】", n); for (int i = 1; i <= n; i++) { p = (LinkList)malloc(sizeof(struct LNode)); scanf_s("%d", &p->data); q->next = p;//将新结点插到表尾 q = q->next;//q指向尾结点,向前进 } q->next = NULL;//最后一个节点的指针域为空 } //算法2.12合并两个有序链表为一个有序链表,借鉴了顺序列表的思想,效率低 void MergerList_L_L(LinkList A, LinkList B, LinkList *C) { //已知条件:单链表A和B中的元素按非递减排序 //输出结果:归并A和B得到新的单链表C,C的元素也按值非递减排序 int sA = ListLength_L(A), sB = ListLength_L(B); int nA = 1, nB = 1, nC = 1; ElemType eA, eB; while (nA <= sA && nB <= sB) { GetElem_L(A, nA, &eA);//在单链表中效率比较低 GetElem_L(B, nB, &eB);//在单链表中效率比较低 if (eA < eB) { ListInsert_L(C, nC, eA); nA++; nC++; } else { ListInsert_L(C, nC, eB); nB++; nC++; } } while (nA <= sA) { GetElem_L(A, nA, &eA); ListInsert_L(C, nC, eA); nA++; nC++; } while (nB <= sB) { GetElem_L(B, nB, &eB); ListInsert_L(C, nC, eB); nB++; nC++; } } //算法2.12合并两个有序链表为一个有序链表,充分利用例链表,效率高 void MergerList_H_L(LinkList A, LinkList *B, LinkList *C) { LinkList pa = A->next, pb = (*B)->next, pc; *C = pc = A; while (pa&&pb) if (pa->data <= pb->data) { pc->next = pa;//将pa所指结点归并到C中 pc = pa;//pc指向表C的最后一个节点 pa = pa->next; } else { pc->next = pb; pc = pb; pb = pb->next; } pc->next = pa ? pa : pb;//插入剩余段 free(*B); //释放B的头结点 (*B) = NULL; }
测试文件 test.c
#include"head.h" void main() /* 除了几个输出语句外,主程和main2-1.c很像 */ { LinkList L; /* 与main2-1.c不同 */ ElemType e, e0; Status i; int j, k; i = InitList_L(&L); for (j = 1; j <= 5; j++) i = ListInsert_L(&L, 1, j); printf("在L的表头依次插入1~5后:L="); ListTraverse_L(L); /* 依次对元素调用visit(),输出元素的值 */ i = ListEmpty_L(L); printf("\nL是否空:i=%d(1:是 0:否)\n", i); i = ClearList_L(&L); printf("清空L后:L="); ListTraverse_L(L); i = ListEmpty_L(L); printf("L是否空:i=%d(1:是 0:否)\n", i); for (j = 1; j <= 10; j++) ListInsert_L(&L, j, j); printf("在L的表尾依次插入1~10后:L="); ListTraverse_L(L); GetElem_L(L, 5, &e); printf("\n第5个元素的值为:%d\n", e); //检测LocateElem_L for (j = 0; j <= 1; j++) { k = LocateElem_L(L, j); if (k) printf("第%d个元素的值为%d\n", k, j); else printf("没有值为%d的元素\n", j); } for (j = 1; j <= 2; j++) /* 测试头两个数据 */ { GetElem_L(L, j, &e0); /* 把第j个数据赋给e0 */ i = PriorElem_L(L, e0, &e); /* 求e0的前驱 */ if (i == INFEASIBLE) printf("元素%d无前驱\n", e0); else printf("元素%d的前驱为:%d\n", e0, e); } for (j = ListLength_L(L) - 1; j <= ListLength_L(L); j++)/*最后两个数据 */ { GetElem_L(L, j, &e0); /* 把第j个数据赋给e0 */ i = NextElem_L(L, e0, &e); /* 求e0的后继 */ if (i == INFEASIBLE) printf("元素%d无后继\n", e0); else printf("元素%d的后继为:%d\n", e0, e); } k = ListLength_L(L); /* k为表长 */ for (j = k + 1; j >= k; j--) { i = ListDelet_L(&L, j, &e); /* 删除第j个数据 */ if (i == ERROR) printf("删除第%d个数据失败\n", j); else printf("删除的元素为:%d\n", e); } printf("依次输出L的元素:"); ListTraverse_L(L); DestoryList_L(&L); printf("\n销毁L后:L=%u\n", L); system("pause"); }
Running result:
在L的表头依次插入1~5后:L=5 4 3 2 1 L是否空:i=0(1:是 0:否) 清空L后:L= L是否空:i=1(1:是 0:否) 在L的表尾依次插入1~10后:L=1 2 3 4 5 6 7 8 9 10 第5个元素的值为:5 没有值为0的元素 第1个元素的值为1 元素1无前驱 元素2的前驱为:1 元素9的后继为:10 元素10无后继 删除第11个数据失败 删除的元素为:10 依次输出L的元素:1 2 3 4 5 6 7 8 9 销毁L后:L=0 请按任意键继续. . .
测试文件 test2.c
#include"head.h" void main() { LinkList A, B, C; LinkList D, E, F; int n = 0; InitList_L(&A); InitList_L(&B); InitList_L(&C); for (int i = 1; i <= 5; i++) ListInsert_L(&A, i, (i + 3)); for (int i = 1; i <= 10; i++) ListInsert_L(&B, i, i); printf("单链表A中的元素有:"); ListTraverse_L(A); printf("\n单链表B中的元素有:"); ListTraverse_L(B); MergerList_L_L(A, B, &C); printf("\n单链表C中的元素有:"); ListTraverse_L(C); printf("\n"); printf("请输入单链表D中的元素个数值n:"); scanf_s("%d", &n); CreateList_F_L(&D, n); printf("请输入单链表E中的元素个数值n:"); scanf_s("%d", &n); CreateList_F_L(&E, n); MergerList_H_L(D, &E, &F); printf("\n单链表F中的元素有:"); ListTraverse_L(F); printf("\n"); system("pause"); }
Running Result:
单链表A中的元素有:4 5 6 7 8 单链表B中的元素有:1 2 3 4 5 6 7 8 9 10 单链表C中的元素有:1 2 3 4 4 5 5 6 6 7 7 8 8 9 10 请输入单链表D中的元素个数值n:3 请输入3个数据【空格键隔开】1 2 3 请输入单链表E中的元素个数值n:3 请输入3个数据【空格键隔开】4 5 6 单链表F中的元素有:1 2 3 4 5 6 请按任意键继续. . .
以上是关于线性表的链式表示和实现----线性(单)链表的主要内容,如果未能解决你的问题,请参考以下文章