一、双向循环链表的结构特点
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); }