头文件 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; } else return 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; else return 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; do p = 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; } }
#include"head.h" Status compare(ElemType c1, ElemType c2) /* c1等于c2 */ { if (c1 == c2) return TRUE; else return FALSE; } int cmp(ElemType a, ElemType b) { /* 根据a<、=或>b,分别返回-1、0或1 */ if (a == b) return 0; else return (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); else printf("链表中没有值为%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)); else printf("表空,无法删除 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); else printf("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); else printf("%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); else printf("%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); else printf("%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"); }
链表中有值为0的元素。 链表中有值为1的元素。 链表中有值为2的元素。 链表中没有值为3的元素。 输出链表:0 1 2 删除表头结点:0 删除表头结点:1 删除表头结点:2 删除表头结点:表空,无法删除 p=0 L中结点个数=0 L是否空 1(1:空 0:否) 输出链表:2 4 6 7 8 10 12 L中不存在值为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 请按任意键继续. . .
#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); else Append(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"); }
La=1 2 3 4 5 Lb=2 4 6 8 10 Lc=1 2 2 3 4 4 5 6 8 10 请按任意键继续. . .