线性表的链式表示和实现----循环(单)链表

<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");
}


Running Result:


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





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值