【2.5】双向循环链表

一、双向循环链表的结构特点

1、每个元素除了拥有指向后继的指针外,还拥有指向前驱的指针;

2、便于元素的逆向查找和遍历;

3、同时具备循环链表的所有优点。

二、双向循环链表的基本结构图

三、文件组织方式

四、代码实现

文件1:utils.h头文件

#ifndef _YE_LELE_02
#define _YE_LELE_02
#include"double_circular_linked_list.h"  
//打印星星
void print_star();

//打印链表内容
void myVisit(int x);

#endif

文件2:utils.cpp函数实现

#include<stdio.h>

void print_star()
{
	printf("**********************\n");
}

void myVisit(int x)
{
	printf("%d\n", x);
}

文件3:double_circular_linked_list.h

#ifndef _YE_LELE_01  
#define _YE_LELE_01 

typedef int ElemType;
typedef int Status;
//双向循环链表的定义
typedef struct DuLNode
{
	ElemType data;
	struct DuLNode *prior;
	struct DuLNode *next;
}DuLNode, *DuLinkList;

void InitList(DuLinkList &L);//循环链表的初始化

void DestoryList(DuLinkList &L);//销毁循环链表

void ClearList(DuLinkList &L);//清空循环链表

Status ListEmpty(DuLinkList L);//判断循环链表元素是否为空

int ListLength(DuLinkList L);//获得循环链表的长度

Status GetElem(DuLinkList L, int loc, ElemType &e);//得到循环链表loc位置的元素并赋值给e

int LocateElem(DuLinkList L, ElemType a);//定位元素a在循环链表的位置

Status PriorElem(DuLinkList L, ElemType a, ElemType &e);//获取链表元素a的前一个节点并赋值给e,返回一个状态

Status NextElem(DuLinkList L, ElemType a, ElemType &e);//获取链表元素a的后一个节点并赋值给e,返回一个状态

Status ListInsert(DuLinkList &L, ElemType a, int loc);//将元素a插入到链表loc的位置

Status ListDelete(DuLinkList &L, ElemType &e, int loc);//删除循环链表loc位置的元素,并将删除的值赋值给e

void ListTraverse(DuLinkList L);//遍历整个循环链表

void ListTraverseBcak(DuLinkList L, void(*visit)(ElemType));//反向遍历整个循环链表

#endif

文件4:double_circular_linked_list.cpp

#include "double_circular_linked_list.h" 
#include <stdlib.h>  
#include <stdio.h>  
//定义状态码  
#define ERROE -2  
#define OVERFLOW -3  
#define OK 1  
#define YES 1  
#define NO 0  
/*
操作结果:产生空的双向链表L,并作为一个不填充数据的空节点
*/
void InitList(DuLinkList &L)//循环链表的初始化
{
	L = (DuLinkList)malloc(sizeof(DuLNode));
	if (L)
	{
		//前驱及后继均指向节点自身
		L->next = L->prior = L;
	}
	else
	{
		//分配失败,内存溢出
		exit(OVERFLOW);
	}
}

void DestoryList(DuLinkList &L)//销毁循环链表
{
	//如果链表本身为空,错误退出  
	if (!L)
	{
		exit(ERROE);
	}
	//释放循环链表指针,释放内存  
	free(L);
}

void ClearList(DuLinkList &L)//清空循环链表
{
	//如果链表本身为空,错误退出  
	if (!L)
	{
		exit(ERROE);
	}
	//重新初始化
	InitList(L);
	printf("循环链表成功清除!\n");
}

Status ListEmpty(DuLinkList L)//判断循环链表元素是否为空
{
	//如果链表本身不存在,错误退出  
	if (!L)
	{
		exit(ERROE);
	}
	//定义一个指针指向首节点  
	DuLinkList p = L;
	if (p->next == L)
	{
		return YES;
	}
	return NO;
}

int ListLength(DuLinkList L)//获得循环链表的长度
{
	//如果链表本身不存在,错误退出  
	if (!L)
	{
		exit(ERROE);
	}
	DuLinkList p = L;
	int count = 0;
	while (true)
	{
		//循环到达首部节点
		if (p->next == L)
		{
			break;
		}
		p = p->next;
		count++;
	}
	return count;
}

Status GetElem(DuLinkList L, int loc, ElemType &e);//得到循环链表loc位置的元素并赋值给e

int LocateElem(DuLinkList L, ElemType a)//定位元素a在循环链表的位置
{
	//定义一个标记,用于指示状态  
	int flag, loc = 0;
	//如果循环链表未初始化,返回错误码  
	if (!L)
	{
		return ERROE;
	}
	//定义一个节点指向循环链表的首节点  
	DuLinkList p = L;
	while (true)
	{
		//如果在n-1个节点内找到该元素  
		if (p->next != L)
		{
			if (p->data == a)
			{
				flag = 1;
				return loc;
			}
			p = p->next;
			loc++;
		}
		//如果表尾元素等于需要判断的元素  
		else if (p->next == L&&p->data == a)
		{
			return loc;
		}
		//如果没有找到该元素  
		else
		{
			flag = -1;
			break;
		}
	}
	if (flag == -1)
	{
		return NO;
	}
}

Status PriorElem(DuLinkList L, ElemType a, ElemType &e)//获取链表元素a的前一个节点并赋值给e,返回一个状态
{
	if (!L)
	{
		exit(ERROE);
	}
	DuLinkList p = L->next;
	//获取元素a在循环链表的位置  
	int position = LocateElem(L, a);
	//获取链表的长度  
	int Length = ListLength(L);
	if (position<1)
	{
		printf("循环链表不存在该元素,无节点值返回\n");
		return NO;
	}
	else
	{
		for (size_t i = 1; i < position; i++)
		{
			p = p->next;
		}
		e = p->prior->data;
	}
	return OK;
}

Status NextElem(DuLinkList L, ElemType a, ElemType &e);//获取链表元素a的后一个节点并赋值给e,返回一个状态

Status ListInsert(DuLinkList &L, ElemType a, int loc)//将元素a插入到链表loc的位置
{
	DuLinkList p = L, s;
	int j;
	//插入位置不合法
	if (loc < 1|| loc > ListLength(L)+1)
	{
		return ERROE;
	}
	//移动节点到需要插入的位置
	for (j = 1; j <= loc-1; j++)
	{
		p = p->next;
	}
	//申请一个节点的空间
	s = (DuLinkList)malloc(sizeof(DuLNode));
	if (!s)
	{
		return OVERFLOW;
	}
	s->data = a;
	s->prior = p;
	s->next = p->next;
	p->next->prior = s;
	p->next = s;
	return OK;
}

Status ListDelete(DuLinkList &L, ElemType &e, int loc)//删除循环链表loc位置的元素,并将删除的值赋值给e
{
	if (!L)
	{
		exit(ERROE);
	}
	DuLinkList  p = L;
	//获取链表的长度  
	int Length = ListLength(L);
	if (loc<1 || loc>Length)
	{
		printf("删除元素的位置不存在\n");
		return ERROE;
	}
	//为了找到上游位置,loc值提前减去1  
	loc--;
	while (loc)
	{
		p = p->next;
		loc--;
	}
	e = p->next->data;
	p->next = p->next->next;
	p->next->next->prior = p;
	return OK;
}


void ListTraverse(DuLinkList L)//遍历整个循环链表
{
	DuLinkList p = L->next;//让p指向首节点
	while (p != L)
	{
		printf("%d\n", p->data);
		p = p->next;
	}
}

void ListTraverseBcak(DuLinkList L,void(*visit)(ElemType))//反向遍历整个循环链表
{
	DuLinkList p = L->prior;//让p指向尾节点
	while (p != L)
	{
		visit(p->data);
		p = p->prior;
	}
}

文件5:main.cpp

#include<stdio.h>  
#include "utils.h"
#include"double_circular_linked_list.h"  
int e;

void test_DuListAppend(DuLinkList &L)
{
	ListInsert(L, 1, 1);
	ListInsert(L, 3, 2);
	ListInsert(L, 5, 3);
	ListInsert(L, 4, 2);
}

void test_ListTraverseBcak(DuLinkList L)
{
	ListTraverseBcak(L,myVisit);
}

void test_ListTraverse(DuLinkList L)
{
	ListTraverse(L);
}

void test_ListDelete(DuLinkList L)
{
	ListDelete(L, e, 4);
	printf("delete ok:");
}

void test_LocateElem(DuLinkList L,ElemType a)
{
	int result = LocateElem(L, a);
	if (result)
	{
		printf("元素%d的位置为%d\n", a, result);
	}
	else
	{
		printf("元素%d在循环链表中不存在!\n", a);
	}
}

void test_PriorElem(DuLinkList L, ElemType a, ElemType &e)
{
	int result = PriorElem(L, a, e);
	if (result)
	{
		printf("元素%d位置之前的元素值为%d\n", a, e);
	}
}

void main()
{
	//1、初始化循环链表  
	print_star();
	DuLinkList L = NULL;
	InitList(L);
	//2、测试插入元素  
	print_star();
	test_DuListAppend(L);
	//3、测试反向打印遍历循环链表的结果  
	print_star();
	test_ListTraverseBcak(L);
	//4、测试打印遍历循环链表的结果  
	print_star();
	test_ListTraverse(L);
	//5、测试按照位置删除元素  
	test_ListDelete(L);
	test_ListTraverse(L);
	//6、测试返回固定元素的位置  
	print_star();
	test_LocateElem(L, 3);
	//7、测试返回链表元素a的前一个节点并赋值给e  
	print_star();
	test_PriorElem(L,1,e);
}

猜你喜欢

转载自blog.csdn.net/yeler082/article/details/80636288