<span style="font-family: Arial, Helvetica, sans-serif;">头文件 head.h</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">#include<string.h></span>
#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_CL{
ElemType data;
struct LNode_CL *next;
}LNode_CL;
typedef struct LNode_CL *LinkList_CL;
Status InitList_CL(LinkList_CL *L);
Status DestoryList_CL(LinkList_CL *L);
Status ClearList_CL(LinkList_CL *L);
Status ListEmpty_CL(LinkList_CL L);
int ListLength_CL(LinkList_CL L);
Status GetElem_CL(LinkList_CL L, int i, ElemType *e);
int LocateElem_CL(LinkList_CL L, ElemType e);
Status PriorElem_CL(LinkList_CL L, ElemType cur_e, ElemType *pre_e);
Status NextElem_CL(LinkList_CL L, ElemType cur_e, ElemType *next_e);
Status ListInsert_CL(LinkList_CL *L, int i, ElemType e);
Status ListDelet_CL(LinkList_CL *L, int i, ElemType *e);
Status ListTraverse_CL(LinkList_CL L);
Status MergeList(LinkList_CL *La, LinkList_CL Lb);
算法实现
#include"head.h"
/*
由于表尾容易找到表头,但若链表较长,则由表头找到表尾比较耗时,
因而,单循环链表往往设立尾指针而不是头指针,其中尾指针指向最后一个结点
也就是说,单循环链表最少应该有一个头结点(不是第一个结点)和尾指针,
因为是循环链表,空表就相当于头结点中的指针是尾指针,非空表则不同!
*/
Status InitList_CL(LinkList_CL *L)
{
//操作结果:构造一个空的线性表L
*L = (LinkList_CL)malloc(sizeof(LNode_CL));
if (!(*L))
{
printf("循环列表初始化失败!\n");
exit(-1);
}
(*L)->next = (*L); //和单链表的不同之处
return OK;
}
Status DestoryList_CL(LinkList_CL *L)
{
//初始条件:线性表L已存在
//操作结果:将L重置为空表
LinkList_CL p, q = (*L)->next;//q指向(*L)的头结点
while (q != (*L))//判定不是空链表!!!!
{
p = q->next;//第一次循环时指的是第一个结点
free(q);
q = p;
}
free(*L);
*L = NULL;//最后别忘了将表制空
return OK;
}
Status ClearList_CL(LinkList_CL *L)
{
//初始条件:线性表L已存在
//操作结果:将L重置为空白
LinkList_CL p, q;
*L = (*L)->next; //*L指向头结点
p = (*L)->next; //p指向第一个结点
while (p != (*L)) //没到表尾!!!!
{
q = p->next;
free(p);
p = q;
}
(*L)->next = (*L);//循环单链表的特点
return OK;
}
Status ListEmpty_CL(LinkList_CL L)
{
//初始条件:线性表已存在
//操作结果:若L为空表,则返回TRUE;否则,返回FALSE
LinkList_CL p = L->next;
if (p != L)
return FALSE;
else
return TRUE;
}
int ListLength_CL(LinkList_CL L)
{
//初始条件:线性表L已存在
//操作结果:返回L中元素的个数
int n = 0;
L = L->next; //指向头结点
LinkList_CL p = L->next; //指向第一个元素
while (p != L) //没有到表尾
{
n++;
p = p->next;
}
return n;
}
Status GetElem_CL(LinkList_CL L, int i, ElemType *e)
{
//初始条件:线性表L已存在, 1<= i <=ListLength(L)+1
//操作结果:用e返回L中第i个数据元素的值
int n = 1;
LinkList_CL p;
if (i<1 || i>ListLength_CL(L) + 1)
return FALSE;
L = L->next;//头结点
p = L->next;//第一个结点
while (n < i)
{
p = p->next;
n++;
}
*e = p->data;
return OK;
}
int LocateElem_CL(LinkList_CL L, ElemType e)
{
int n = 1;
LinkList_CL p;
L = L->next; //头结点
p = L->next; //第一个结点
while (p != L)
{
if ((p->data) == e)
return n;
n++;
p = p->next;
}
return 0;
}
Status PriorElem_CL(LinkList_CL L, ElemType cur_e, ElemType *pre_e)
{
LinkList_CL p, q;
p = L->next->next; //第一个元素
q = p->next;//第二个元素
while (q != L->next)//没有到表尾
{
if (q->data == cur_e)
{
*pre_e = p->data;
return TRUE;
}
p = q;
q = q->next;
}
return FALSE;
}
Status NextElem_CL(LinkList_CL L, ElemType cur_e, ElemType *next_e)
{
LinkList_CL p;
p = L->next; p = p->next;//指向第一个元素
while (p != L)//没有到表尾
{
if (p->data == cur_e)
{
p = p->next;
*next_e = p->data;
return TRUE;
}
p = p->next;
}
return FALSE;
}
Status ListInsert_CL(LinkList_CL *L, int i, ElemType e)
{
int n = 1;
LinkList_CL t = (*L)->next; //t代表头结点
LinkList_CL s;
if (i<1 || i>ListLength_CL(*L) + 1)
return FALSE;
while (n < i) //找到i之前的那一个位置
{
t = t->next;
n++;
}
s = (LinkList_CL)malloc(sizeof(LNode_CL));
s->data = e;
s->next = t->next; //由后向前处理数据
t->next = s;
if (t == *L) //改变尾结点????
//如果在表尾处插入该元素,则应该改变尾指针是指指向新增加的元素
*L = s;
return OK;
}
Status ListDelet_CL(LinkList_CL *L, int i, ElemType *e)
{
LinkList_CL p = (*L)->next, t; //p为头结点
int n = 1;
if (i<1 || i>ListLength_CL(*L))
return FALSE;
while (n < i) //找到i之前的那个位置
{
p = p->next;
n++;
}
t = p->next;
*e = t->data;
p->next = t->next;
//如果删除是表尾元素
if (*L = t)
//则尾指针指向被删除元素(表尾元素)的前一个结点的指针
*L = p;
free(t);
return OK;
}
Status ListTraverse_CL(LinkList_CL L)
{
LinkList_CL p;
L = L->next;//头结点
p = L->next;//第一个结点
while (p != L)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
return OK;
}
Status MergeList(LinkList_CL *La, LinkList_CL Lb)
{
<span style="white-space:pre"> </span>//将Lb合并到La的表尾,由La指示新表, 中间两行注释的代码有些冗余,因为尾指针的下一个元素是头结点是循环链表固有的属性!
<span style="white-space:pre"> </span>LinkList_CL p = Lb->next;<span style="white-space:pre"> </span>//指向Lb的头结点
//<span style="white-space:pre"> </span>LinkList_CL q = (*La)->next;
<span style="white-space:pre"> </span>Lb->next = (*La)->next;
<span style="white-space:pre"> </span>(*La)->next = p->next;<span style="white-space:pre"> </span>//Lb的头结点是多余的,去除即可
<span style="white-space:pre"> </span>free(p);
//<span style="white-space:pre"> </span>Lb->next = q;
<span style="white-space:pre"> </span>(*La) = Lb;<span style="white-space:pre"> </span>//改变La的尾指针
<span style="white-space:pre"> </span>return OK;
}
测试文件1 test.c
#include"head.h"
void main() /* 除了几个输出语句外,主程和main2-1.c很像 */
{
LinkList_CL L; /* 与main2-1.c不同 */
ElemType e, e0;
Status i;
int j, k;
i = InitList_CL(&L);
for (j = 1; j <= 5; j++)
i = ListInsert_CL(&L, 1, j);
printf("在L的表头依次插入1~5后:L=");
ListTraverse_CL(L); /* 依次对元素调用visit(),输出元素的值 */
i = ListEmpty_CL(L);
printf("\nL是否空:i=%d(1:是 0:否)\n", i);
i = ClearList_CL(&L);
printf("清空L后:L=");
ListTraverse_CL(L);
i = ListEmpty_CL(L);
printf("L是否空:i=%d(1:是 0:否)\n", i);
for (j = 1; j <= 10; j++)
ListInsert_CL(&L, j, j);
printf("在L的表尾依次插入1~10后:L=");
ListTraverse_CL(L);
GetElem_CL(L, 5, &e);
printf("\n第5个元素的值为:%d\n", e);
//检测LocateElem_L
for (j = 0; j <= 1; j++)
{
k = LocateElem_CL(L, j);
if (k)
printf("第%d个元素的值为%d\n", k, j);
else
printf("没有值为%d的元素\n", j);
}
for (j = 1; j <= 2; j++) /* 测试头两个数据 */
{
GetElem_CL(L, j, &e0); /* 把第j个数据赋给e0 */
i = PriorElem_CL(L, e0, &e); /* 求e0的前驱 */
if (i == FALSE)
printf("元素%d无前驱\n", e0);
else
printf("元素%d的前驱为:%d\n", e0, e);
}
for (j = ListLength_CL(L) - 1; j <= ListLength_CL(L); j++)/*最后两个数据 */
{
// printf("j=%d\n", j);
GetElem_CL(L, j, &e0); /* 把第j个数据赋给e0 */
// printf("元素wei%d\n", e0);
i = NextElem_CL(L, e0, &e); /* 求e0的后继 */
if (i == FALSE)
printf("元素%d无后继\n", e0);
else
printf("元素%d的后继为:%d\n", e0, e);
}
k = ListLength_CL(L); /* k为表长 */
for (j = k + 1; j >= k; j--)
{
i = ListDelet_CL(&L, j, &e); /* 删除第j个数据 */
if (i == FALSE)
printf("删除第%d个数据失败\n", j);
else
printf("删除的元素为:%d\n", e);
}
printf("依次输出L的元素:");
ListTraverse_CL(L);
DestoryList_CL(&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
请按任意键继续. . .
测试文件2 test2.c
#include"head.h"
void main() /* 除了几个输出语句外,主程和main2-1.c很像 */
{
int n = 5;
LinkList_CL La, Lb;
//初始化La
InitList_CL(&La);
for (int i = 1; i <= n; i++)
ListInsert_CL(&La, i, i);
printf("La = ");
ListTraverse_CL(La);
//初始化Lb
InitList_CL(&Lb);
for (int i = 1; i <= n; i++)
ListInsert_CL(&Lb, i, i*2);
printf("Lb = ");
ListTraverse_CL(Lb);
if (MergeList(&La, Lb))
{
printf("La + Lb = ");
ListTraverse_CL(La);
}
system("pause");
}
La = 1 2 3 4 5
Lb = 2 4 6 8 10
La + Lb = 1 2 3 4 5 2 4 6 8 10
请按任意键继续. . .