线性表的链式表示和实现----实用算法

来源:互联网 发布:teamview linux无桌面 编辑:程序博客网 时间:2024/05/23 21:19



头文件 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, *Link, *Position;typedef struct LinkList //链表类型{Link head, tail;//分别指向线性链表中的头结点和最后一个结点int len;//指示线性链表中数据元素的个数}LinkList;Status MakeNode(Link *p, ElemType e);void FreeNode(Link *p);Status InitList(LinkList *L);Status ClearList(LinkList *L);Status DestroyList(LinkList *L);Status InsFirst(LinkList *L, Link h, Link s);Status DelFirst(LinkList *L, Link h, Link *q);Status Append(LinkList *L, Link s);Position PriorPos(LinkList L, Link p);Status Remove(LinkList *L, Link *q);Status InsBefore(LinkList *L, Link *p, Link s);Status InsAfter(LinkList *L, Link *p, Link s);Status SetCurElem(Link p, ElemType e);ElemType GetCurElem(Link p);Status ListEmpty(LinkList L);int ListLength(LinkList L);Position GetHead(LinkList L);Position GetLast(LinkList L);Position NextPos(Link p);Status LocatePos(LinkList L, int i, Link *p);Position LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType));Status ListTraverse(LinkList L, void(*visit)(ElemType));Status OrderInsert(LinkList *L, ElemType e, int(*comp)(ElemType, ElemType));Status LocateElemP(LinkList L, ElemType e, Position *q, int(*compare)(ElemType, ElemType));

实现算法:


#include"head.h"/* 具有实用意义的线性链表的24个基本操作 */Status MakeNode(Link *p, ElemType e){ //分配由p指向的值为e的结点,并返回OK;若分配失败。则返回ERROR *p = (Link)malloc(sizeof(LNode));if (!*p){printf("构造结点时分配空间失败!\n");return ERROR;}(*p)->data = e;return OK;}void FreeNode(Link *p){ //释放p所指结点free(*p);*p = NULL;}Status InitList(LinkList *L){ //构造一个空的线性链表Link p;p = (Link)malloc(sizeof(LNode));//生成头结点if (p){p->next = NULL;(*L).head = (*L).tail = p;//只是指向头结点和尾结点而已,不用分配内存空间(*L).len = 0;return OK;}else{printf("构造线性链表时分配空间失败!");return ERROR;}}Status ClearList(LinkList *L){ //将线性链表L重置为空表,并释放原链表的结点空间Link p, q;if ((*L).head != (*L).tail)//不是空表{p = q = (*L).head->next;(*L).head->next = NULL;while (p != (*L).tail){p = q->next;free(q);q = p;}free(q);(*L).tail = (*L).head;(*L).len = 0;}return OK;}Status DestroyList(LinkList *L){ //销毁线性链表L,L不再存在ClearList(L);//清空链表FreeNode(&(*L).head);(*L).tail = NULL;(*L).len = 0;return OK;}Status InsFirst(LinkList *L, Link h, Link s) //形参增加L,因为需修改L{ //h指向L的一个结点,把h当做头结点,将s所指结点插入在第一个结点之前s->next = h->next;h->next = s;if (h == (*L).tail)//h指向尾结点(*L).tail = h->next;//修改尾指针(*L).len++;return OK;}Status DelFirst(LinkList *L, Link h, Link *q) /* 形参增加L,因为需修改L */{ /* h指向L的一个结点,把h当做头结点,删除链表中的第一个结点并以q返回。 *//* 若链表为空(h指向尾结点),q=NULL,返回FALSE */*q = h->next;if (*q) /* 链表非空 */{h->next = (*q)->next;if (!h->next) /* 删除尾结点 */(*L).tail = h; /* 修改尾指针 */(*L).len--;return OK;}elsereturn FALSE; /* 链表空 */}Status Append(LinkList *L, Link s){ /* 将指针s(s->data为第一个数据元素)所指(彼此以指针相链,以NULL结尾)的 *//* 一串结点链接在线性链表L的最后一个结点之后,并改变链表L的尾指针指向新 *//* 的尾结点 */int i = 1;(*L).tail->next = s;while (s->next){s = s->next;i++;}(*L).tail = s;(*L).len += i;return OK;}Position PriorPos(LinkList L, Link p){ /* 已知p指向线性链表L中的一个结点,返回p所指结点的直接前驱的位置 *//* 若无前驱,则返回NULL */Link q;q = L.head->next;if (q == p) /* 无前驱 */return NULL;else{while (q->next != p) /* q不是p的直接前驱 */q = q->next;return q;}}Status Remove(LinkList *L, Link *q){ /* 删除线性链表L中的尾结点并以q返回,改变链表L的尾指针指向新的尾结点 */Link p = (*L).head;if ((*L).len == 0) /* 空表 */{*q = NULL;return FALSE;}while (p->next != (*L).tail)p = p->next;*q = (*L).tail;p->next = NULL;(*L).tail = p;(*L).len--;return OK;}Status InsBefore(LinkList *L, Link *p, Link s){ /* 已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之前, *//* 并修改指针p指向新插入的结点 */Link q;q = PriorPos(*L, *p); /* q是p的前驱 */if (!q) /* p无前驱 */q = (*L).head;s->next = *p;q->next = s;*p = s;(*L).len++;return OK;}Status InsAfter(LinkList *L, Link *p, Link s){ /* 已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之后, *//* 并修改指针p指向新插入的结点 */if (*p == (*L).tail) /* 修改尾指针 */(*L).tail = s;s->next = (*p)->next;(*p)->next = s;*p = s;(*L).len++;return OK;}Status SetCurElem(Link p, ElemType e){ /* 已知p指向线性链表中的一个结点,用e更新p所指结点中数据元素的值 */p->data = e;return OK;}ElemType GetCurElem(Link p){ /* 已知p指向线性链表中的一个结点,返回p所指结点中数据元素的值 */return p->data;}Status ListEmpty(LinkList L){ /* 若线性链表L为空表,则返回TRUE,否则返回FALSE */if (L.len)return FALSE;elsereturn TRUE;}int ListLength(LinkList L){ /* 返回线性链表L中元素个数 */return L.len;}Position GetHead(LinkList L){ /* 返回线性链表L中头结点的位置 */return L.head;}Position GetLast(LinkList L){ /* 返回线性链表L中最后一个结点的位置 */return L.tail;}Position NextPos(Link p){ /* 已知p指向线性链表L中的一个结点,返回p所指结点的直接后继的位置 *//* 若无后继,则返回NULL */return p->next;}Status LocatePos(LinkList L, int i, Link *p){ /* 返回p指示线性链表L中第i个结点的位置,并返回OK,i值不合法时返回ERROR *//* i=0为头结点 */int j;if (i<0 || i>L.len)return ERROR;else{*p = L.head;for (j = 1; j <= i; j++)*p = (*p)->next;return OK;}}Position LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType)){ /* 返回线性链表L中第1个与e满足函数compare()判定关系的元素的位置, *//* 若不存在这样的元素,则返回NULL */Link p = L.head;dop = p->next;while (p&&!(compare(p->data, e))); /* 没到表尾且没找到满足关系的元素 */return p;}Status ListTraverse(LinkList L, void(*visit)(ElemType)){ /* 依次对L的每个数据元素调用函数visit()。一旦visit()失败,则操作失败 */Link p = L.head->next;int j;for (j = 1; j <= L.len; j++){visit(p->data);p = p->next;}printf("\n");return OK;}Status OrderInsert(LinkList *L, ElemType e, int(*comp)(ElemType, ElemType)){ /* 已知L为有序线性链表,将元素e按非降序插入在L中。(用于一元多项式) */Link o, p, q;q = (*L).head;p = q->next;while (p != NULL&&comp(p->data, e)<0) /* p不是表尾且元素值小于e */{q = p;p = p->next;}o = (Link)malloc(sizeof(LNode)); /* 生成结点 */o->data = e; /* 赋值 */q->next = o; /* 插入 */o->next = p;(*L).len++; /* 表长加1 */if (!p) /* 插在表尾 */(*L).tail = o; /* 修改尾结点 */return OK;}Status LocateElemP(LinkList L, ElemType e, Position *q, int(*compare)(ElemType, ElemType)){ /* 若升序链表L中存在与e满足判定函数compare()取值为0的元素,则q指示L中 *//* 第一个值为e的结点的位置,并返回TRUE;否则q指示第一个与e满足判定函数 *//* compare()取值>0的元素的前驱的位置。并返回FALSE。(用于一元多项式) */Link p = L.head, pp;do{pp = p;p = p->next;} while (p && (compare(p->data, e)<0)); /* 没到表尾且p->data.expn<e.expn */if (!p || compare(p->data, e)>0) /* 到表尾或compare(p->data,e)>0 */{*q = pp;return FALSE;}else /* 找到 */{*q = p;return TRUE;}}


测试文件 test.c


#include"head.h"Status compare(ElemType c1, ElemType c2) /* c1等于c2 */{if (c1 == c2)return TRUE;elsereturn FALSE;}int cmp(ElemType a, ElemType b){ /* 根据a<、=或>b,分别返回-1、0或1 */if (a == b)return 0;elsereturn (a - b) / abs(a - b);}void visit(ElemType c){printf("%d ", c);}void main(){Link p, h;LinkList L;Status i;int j, k;i = InitList(&L);if (!i) /* 初始化空的线性表L不成功 */exit(FALSE); /* 退出程序运行 */for (j = 1; j <= 2; j++){MakeNode(&p, j); /* 生成由p指向、值为j的结点 */InsFirst(&L, L.tail, p); /* 插在表尾 */}OrderInsert(&L, 0, cmp); /* 按升序插在有序表头 */for (j = 0; j <= 3; j++){i = LocateElemP(L, j, &p, cmp);if (i)printf("链表中有值为%d的元素。\n", p->data);elseprintf("链表中没有值为%d的元素。\n", j);}printf("输出链表:");ListTraverse(L, visit); /* 输出L */for (j = 1; j <= 4; j++){printf("删除表头结点:");DelFirst(&L, L.head, &p); /* 删除L的首结点,并以p返回 */if (p)printf("%d\n", GetCurElem(p));elseprintf("表空,无法删除 p=%u\n", p);}printf("L中结点个数=%d L是否空 %d(1:空 0:否)\n", ListLength(L), ListEmpty(L));MakeNode(&p, 10);p->next = NULL; /* 尾结点 */for (j = 4; j >= 1; j--){MakeNode(&h, j * 2);h->next = p;p = h;} /* h指向一串5个结点,其值依次是2 4 6 8 10 */Append(&L, h); /* 把结点h链接在线性链表L的最后一个结点之后 */OrderInsert(&L, 12, cmp); /* 按升序插在有序表尾头 */OrderInsert(&L, 7, cmp); /* 按升序插在有序表中间 */printf("输出链表:");ListTraverse(L, visit); /* 输出L */for (j = 1; j <= 2; j++){p = LocateElem(L, j * 5, compare);if (p)printf("L中存在值为%d的结点。\n", j * 5);elseprintf("L中不存在值为%d的结点。\n", j * 5);}for (j = 1; j <= 2; j++){LocatePos(L, j, &p); /* p指向L的第j个结点 */h = PriorPos(L, p); /* h指向p的前驱 */if (h)printf("%d的前驱是%d。\n", p->data, h->data);elseprintf("%d没前驱。\n", p->data);}k = ListLength(L);for (j = k - 1; j <= k; j++){LocatePos(L, j, &p); /* p指向L的第j个结点 */h = NextPos(p); /* h指向p的后继 */if (h)printf("%d的后继是%d。\n", p->data, h->data);elseprintf("%d没后继。\n", p->data);}printf("L中结点个数=%d L是否空 %d(1:空 0:否)\n", ListLength(L), ListEmpty(L));p = GetLast(L); /* p指向最后一个结点 */SetCurElem(p, 15); /* 将最后一个结点的值变为15 */printf("第1个元素为%d 最后1个元素为%d\n", GetCurElem(GetHead(L)->next), GetCurElem(p));MakeNode(&h, 10);InsBefore(&L, &p, h); /* 将10插到尾结点之前,p指向新结点 */p = p->next; /* p恢复为尾结点 */MakeNode(&h, 20);InsAfter(&L, &p, h); /* 将20插到尾结点之后 */k = ListLength(L);printf("依次删除表尾结点并输出其值:");for (j = 0; j <= k; j++){i = Remove(&L, &p);if (!i) /* 删除不成功 */printf("删除不成功 p=%u\n", p);elseprintf("%d ", p->data);}MakeNode(&p, 29); /* 重建具有1个结点(29)的链表 */InsFirst(&L, L.head, p);DestroyList(&L); /* 销毁线性链表L */printf("销毁线性链表L之后: L.head=%u L.tail=%u L.len=%d\n", L.head, L.tail, L.len);system("pause");}

Running Result:


链表中有值为0的元素。链表中有值为1的元素。链表中有值为2的元素。链表中没有值为3的元素。输出链表:0 1 2删除表头结点:0删除表头结点:1删除表头结点:2删除表头结点:表空,无法删除 p=0L中结点个数=0 L是否空 1(1:空 0:否)输出链表:2 4 6 7 8 10 12L中不存在值为5的结点。L中存在值为10的结点。2没前驱。4的前驱是2。10的后继是12。12没后继。L中结点个数=7 L是否空 0(1:空 0:否)第1个元素为2 最后1个元素为15依次删除表尾结点并输出其值:20 15 10 10 8 7 6 4 2 删除不成功 p=0销毁线性链表L之后: L.head=0 L.tail=0 L.len=0请按任意键继续. . .

测试文件 二 test2.c


#include"head.h"Status ListInsert_L(LinkList *L, int i, ElemType e) /* 算法2.20 */{ /* 在带头结点的单链线性表L的第i个元素之前插入元素e */Link h, s;if (!LocatePos(*L, i - 1, &h))return ERROR; /* i值不合法 */if (!MakeNode(&s, e))return ERROR; /* 结点分配失败 */InsFirst(L, h, s); /*对于从第i个结点开始的链表,第i-1个结点是它的头结点 */return OK;}Status MergeList_L(LinkList La, LinkList Lb, LinkList *Lc, int(*compare)(ElemType, ElemType)){ /* 已知单链线性表La和Lb的元素按值非递减排列。归并La和Lb得到新的单链 *//* 线性表Lc,Lc的元素也按值非递减排列。(不改变La、Lb)算法2.21 */Link ha, hb, pa, pb, q;ElemType a, b;if (!InitList(Lc))return ERROR; /* 存储空间分配失败 */ha = GetHead(La); /* ha和hb分别指向La和Lb的头结点 */hb = GetHead(Lb);pa = NextPos(ha); /* pa和pb分别指向La和Lb的第一个结点 */pb = NextPos(hb);while (!ListEmpty(La) && !ListEmpty(Lb)) /* La和Lb均非空 */{a = GetCurElem(pa); /* a和b为两表中当前比较元素 */b = GetCurElem(pb);if (compare(a, b) <= 0){DelFirst(&La, ha, &q);InsFirst(Lc, (*Lc).tail, q);pa = NextPos(ha);}else /* a>b */{DelFirst(&Lb, hb, &q);InsFirst(Lc, (*Lc).tail, q);pb = NextPos(hb);}}if (!ListEmpty(La))Append(Lc, pa);elseAppend(Lc, pb);FreeNode(&ha);FreeNode(&hb);return OK;}int comp(ElemType c1, ElemType c2){return c1 - c2;}void visit(ElemType c){printf("%d ", c); /* 整型 */}void main(){LinkList La, Lb, Lc;int j;InitList(&La);for (j = 1; j <= 5; j++)ListInsert_L(&La, j, j); /* 顺序插入 1 2 3 4 5 */printf("La=");ListTraverse(La, visit);InitList(&Lb);for (j = 1; j <= 5; j++)ListInsert_L(&Lb, j, 2 * j); /* 顺序插入 2 4 6 8 10 */printf("Lb=");ListTraverse(Lb, visit);InitList(&Lc);MergeList_L(La, Lb, &Lc, comp); /* 归并La和Lb,产生Lc */printf("Lc=");ListTraverse(Lc, visit);DestroyList(&Lc);system("pause");}

Running Result:


La=1 2 3 4 5Lb=2 4 6 8 10Lc=1 2 2 3 4 4 5 6 8 10请按任意键继续. . .



0 0
原创粉丝点击