目录
一、循环双链表
1、循环双链表的定义:
循环双链表是一种特殊的双链表,其特点是尾节点的指针域指向头结点,形成一个环状结构。这种数据结构允许从链表的任意节点出发,通过后移操作,遍历整个循环双链表。
2、循环双链表的优缺点:
循环双链表的优点:
- 可以从任意节点出发,遍历整个链表,提高了遍历的灵活性。
- 在某些应用场景中,循环双链表可以提供更高的访问效率。
循环双链表的缺点:
- 插入和删除节点需要更多的时间来调整指针,因为需要维护链表的环状结构。
- 循环双链表的空间利用率相对较低,因为需要额外的指针来存储前驱和后继节点的信息。
二、循环双链表的基本操作算法(C语言)
1、宏定义
#define OK 1
#define ERROR 0
typedef char ElemType;
typedef int Status;
2、创建结构体
/**定义一个具有前驱指针和后继指针的双链表的结构体**/
typedef struct DuLNode {
ElemType data; //数据域
struct DuLNode *prior; //指向直接前驱
struct DuLNode *next; //指向直接后继
// struct DuLNode *prior,*next; //前驱指针和后继指针
} DuLNode, *DuLinkList; //前者强调这是结点,后者强调这是链表
3、循环双链表的初始化
//循环双链表初始化
Status InitList(DuLinkList &head) {
head = new DuLNode;
head->prior = head;//循环双链表
head->next = head;
return OK;
}
4、循环双链表按位查找
//按位查找
DuLNode *GetElem(DuLinkList L, int i) {
int j = 1;//因为有头结点,所以从1开始遍历
if (i < 1) {//判断查找的位置是否合法
printf("数值非法");
}
DuLNode *p = L->next;//初始化结点指针
while (p != NULL && j < i) {
p = p->next;
j++;
}
return p;
}
5、循环双链表插入
//插入
Status ListInsert_Dul(DuLinkList &head, int i, ElemType e) {
DuLinkList p = head;
int j=0;
while (p && (j<i-1)){
p=p->next;
j++;
}
if (!p || j > i-1){
return ERROR;
}
//DuLinkList p = GetElem(head, i);
if (!p) {
return ERROR;
}
DuLNode *s = new DuLNode;
s->data = e;
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
return OK;
}
6、循环双链表查找
//查找
int LocateLinkListElem(DuLinkList head, ElemType e) {
DuLinkList p = head->next;
int j = 1;
while (p != head && (p->data != e)) {//p != L p!=NULL
p = p->next;
j++;
}
if (p == head) { //p==L !p<=>p==NULL
return 0;
}
return j;
}
7、循环双链表删除
//删除
Status ListDelete_DuL(DuLinkList &head, int i, ElemType &e) {
DuLinkList p=head;
int j=0;
while (p->next != head && j <= i){ //p != L
p=p->next;
j++;
}
if (p->next == head){ //p==L
return ERROR;
}
//调用按位查找函数
// DuLinkList p = GetElem(head, i);
if (!p) {
return ERROR;
}
e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
delete p;
return OK;
}
8、求循环双链表长度
//求双链表长度
Status GetLinkListLength(DuLinkList head) {
DuLinkList p = head->next;
int length = 0;
while (p != head) { //p!=NULL //单链表不为空表时
length++;
p = p->next;
}
return length;
}
9、循环双链表清空
//清空
Status ClearList(DuLinkList &head) {
DuLinkList p = head->next;
DuLinkList q;
while (p != head) { //p != L p!=NULL
q = p;
p = p->next;
delete q;
}
head->prior = head;
head->next = head; //链表为空
return OK;
}
10、循环双链表销毁
//销毁
Status DestroyList(DuLinkList &head) {
DuLinkList p, q;//初始化两个指针,p用来free释放,q用来在p释放后将p指针指向下一个
p = head->next;//删除带头链表头结点不删除
q = p;
while (p != head) {
q = p->next; //提前将q指向下一个
delete p; //释放p
p = q; //将p指向q所指向的下一个
}
head->next = NULL; //头结点指向NULL
return OK;
//printf("\n销毁成功\n");
}
11、头插法建立循环双链表
void CreateDLinkList_H(DuLinkList &head, int n) {
InitList(head);
for (int i = 0; i < n; i++) {
DuLNode *p = new DuLNode;
//scanf("%c",&p->data);
p->data = getche();
//cin >> p->data;
p->next = head->next;
if (head->next != NULL) {
head->next->prior = p;
}
p->prior = head;
head->next = p;
}
}
12、尾头插法建立循环双链表
void CreateDoubleList_R(DuLinkList &head, int n) {
InitList(head);
DuLinkList r = head; // 初始化 r 指针为头结点
for (int i = 0; i < n; i++) {
DuLNode *p = new DuLNode;
//scanf("%c",&p->data);
p->data = getche();
//cin >> p->data;
//p->next=NULL p->next=head
p->next = r->next;
if (r->next != NULL) {
r->next->prior = p;
}
p->prior = r;
r->next = p;
r = p; // r 指向新插入的节点,更新尾指针
}
r->next = head; // 将尾节点的 next 指针指向头结点,形成循环
}
13、输出链表元素
//输出链表元素
void printLinkList(DuLinkList head) {
DuLinkList p = head->next;
while (p != head) { //p != L
printf("%c", p->data);
p = p->next;
}
printf("\n");
}
三、循环双链表的基本操作 完整代码**(C语言)**
#include <stdio.h>
#include <conio.h>//getche()
#define OK 1
#define ERROR 0
typedef char ElemType;
typedef int Status;
/**定义一个具有前驱指针和后继指针的双链表的结构体**/
typedef struct DuLNode {
ElemType data; //数据域
struct DuLNode *prior; //指向直接前驱
struct DuLNode *next; //指向直接后继
// struct DuLNode *prior,*next; //前驱指针和后继指针
} DuLNode, *DuLinkList; //前者强调这是结点,后者强调这是链表
//双链表初始化
Status InitList(DuLinkList &head) {
head = new DuLNode;
head->prior = head;//循环双链表
head->next = head;
// head->prior = NULL;
// head->next = NULL;
return OK;
}
//功能菜单
int choice() {
printf("==================================\n");
printf(" 双链表操作功能菜单 \n");
printf("1、插入元素 2、查询表长 3、按位查找\n");
printf("4、按值查找 5、删除元素 6、销毁链表\n");
printf("7、清空链表 8、批量插入 9、链表元素\n");
printf("10、头插法创建双链表11、尾插法创建双链表\n");
printf("==================================\n");
return 0;
}
//按位查找
DuLNode *GetElem(DuLinkList L, int i) {
int j = 1;//因为有头结点,所以从1开始遍历
if (i < 1) {//判断查找的位置是否合法
printf("数值非法");
}
DuLNode *p = L->next;//初始化结点指针
while (p != NULL && j < i) {
p = p->next;
j++;
}
return p;
}
//插入
Status ListInsert_Dul(DuLinkList &head, int i, ElemType e) {
// DuLinkList p = head;
// int j=0;
// while (p && (j<i-1)){
// p=p->next;
// j++;
// }
// if (!p || j > i-1){
// return ERROR;
// }
DuLinkList p = GetElem(head, i);
if (!p) {
return ERROR;
}
DuLNode *s = new DuLNode;
s->data = e;
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
return OK;
}
//查找
int LocateLinkListElem(DuLinkList head, ElemType e) {
DuLinkList p = head->next;
int j = 1;
while (p != head && (p->data != e)) {//p != L p!=NULL
p = p->next;
j++;
}
if (p == head) { //p==L !p<=>p==NULL
return 0;
}
return j;
}
//删除
Status ListDelete_DuL(DuLinkList &head, int i, ElemType &e) {
// DuLinkList p=head;
// int j=0;
// while (p->next != head && j <= i){ //p != L
// p=p->next;
// j++;
// }
// if (p->next == head){ //p==L
// return ERROR;
// }
//调用按位查找函数
DuLinkList p = GetElem(head, i);
if (!p) {
return ERROR;
}
e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
delete p;
return OK;
}
//求双链表长度
Status GetLinkListLength(DuLinkList head) {
DuLinkList p = head->next;
int length = 0;
while (p != head) { //p!=NULL //单链表不为空表时
length++;
p = p->next;
}
return length;
}
//清空
Status ClearList(DuLinkList &head) {
DuLinkList p = head->next;
DuLinkList q;
while (p != head) { //p != L p!=NULL
q = p;
p = p->next;
delete q;
}
head->prior = head;
head->next = head; //链表为空
return OK;
}
//销毁
Status DestroyList(DuLinkList &head) {
DuLinkList p, q;//初始化两个指针,p用来free释放,q用来在p释放后将p指针指向下一个
p = head->next;//删除带头链表头结点不删除
q = p;
while (p != head) {
q = p->next; //提前将q指向下一个
delete p; //释放p
p = q; //将p指向q所指向的下一个
}
head->next = NULL; //头结点指向NULL
return OK;
//printf("\n销毁成功\n");
}
//头插法创建循环双链表
void CreateDLinkList_H(DuLinkList &head, int n) {
InitList(head);
for (int i = 0; i < n; i++) {
DuLNode *p = new DuLNode;
//scanf("%c",&p->data);
p->data = getche();
//cin >> p->data;
p->next = head->next;
if (head->next != NULL) {
head->next->prior = p;
}
p->prior = head;
head->next = p;
}
}
//尾插法创建循环双链表
void CreateDoubleList_R(DuLinkList &head, int n) {
InitList(head);
DuLinkList r = head; // 初始化 r 指针为头结点
for (int i = 0; i < n; i++) {
DuLNode *p = new DuLNode;
//scanf("%c",&p->data);
p->data = getche();
//cin >> p->data;
//p->next=NULL p->next=head
p->next = r->next;
if (r->next != NULL) {
r->next->prior = p;
}
p->prior = r;
r->next = p;
r = p; // r 指向新插入的节点,更新尾指针
}
r->next = head; // 将尾节点的 next 指针指向头结点,形成循环
}
//输出链表元素
void printLinkList(DuLinkList head) {
DuLinkList p = head->next;
while (p != head) { //p != L
printf("%c", p->data);
p = p->next;
}
printf("\n");
}
int main() {
DuLinkList list;
printf("双链表正在初始化....\n");
int InitStatus = InitList(list);
if (InitStatus == OK) {
printf("双链表初始化成功!\n");
} else {
printf("双链表初始化失败!\n");
}
choice();
while (1) {
int flag;
printf("请输入所需的功能编号:\n");
scanf("%d", &flag);
switch (flag) {//通过开关进行功能选择
case 1: {//插入元素
//ListInsert_Dul(list,1,'a');
int insertIndex;
ElemType inserElem;
printf("请输入插入元素位置及插入元素(请在英文状态下输入例如:1,a): \n");
scanf("%d,%c", &insertIndex, &inserElem);
Status InsertS = ListInsert_Dul(list, insertIndex, inserElem);
if (InsertS == OK) {
printf("向双循环链表%d个位置,插入元素为%c成功!\n\n", insertIndex, inserElem);
} else {
printf("向双循环链表插入元素失败!\n\n");
}
}
break;
case 2: {//求单链表的长度
int length = GetLinkListLength(list);
printf("循环双链表的长度为:%d。 \n\n", length);
}
break;
case 3: {//取值
Status GetIndex;
printf("请输入需要查询的元素的位置:\n");
scanf("%d", &GetIndex);
DuLinkList GetStatus = GetElem(list, GetIndex);
ElemType GetElem = GetStatus->data;
if (GetStatus != NULL) {
printf("从双链表中获取第%d位置元素成功,所获取到的元素为:%c。\n\n", GetIndex, GetElem);
} else {
printf("从双链表中获取第%d位置元素失败!\n\n", GetIndex);
}
}
break;
case 4: {//查找
ElemType LocateElem;
printf("请输入想要查找元素:\n");
getchar(); //用于接收回车
scanf("%c", &LocateElem);
Status LocateIndex = LocateLinkListElem(list, LocateElem);
if (LocateIndex > 0) {
printf("从双链表中查找元素%c成功,它在循环链表中的位置为第%d个!\n\n", LocateElem, LocateIndex);
} else {
printf("从双链表中查找元素%c失败!\n\n", LocateElem);
}
}
break;
case 5: {//删除
//ListDelete_DuL(list,1);
Status DeleteIndex;
printf("请输入想要删除元素的位置:\n");
scanf("%d", &DeleteIndex);
ElemType DeleteElem;
ElemType DeleteStatus = ListDelete_DuL(list, DeleteIndex, DeleteElem);
if (DeleteStatus == OK) {
printf("删除双链表第%d个位置的元素成功,删除的元素为:%c。\n\n", DeleteIndex, DeleteElem);
} else {
printf("删除双链表第%d个位置的元素失败!\n\n", DeleteIndex);
}
}
break;
case 6: {//销毁
Status DestoryStatus = DestroyList(list);
if (DestoryStatus == OK) {
printf("双环链表销毁成功!\n\n");
} else {
printf("双链表销毁失败!\n\n");
}
}
break;
case 7: {//清空
Status ClearStatus = ClearList(list);
if (ClearStatus == OK) {
printf("双链表清空成功!\n\n");
} else {
printf("双链表清空失败!\n\n");
}
}
break;
case 8: {//批量插入
int on;
printf("请输入想要插入的元素个数:\n");
scanf("%d", &on);
ElemType array[on];
for (int i = 1; i <= on; i++) {
getchar();
printf("向双链表第%d个位置插入元素为:", (i));
scanf("%c", &array[i]);
}
for (int i = 1; i <= on; i++) {
Status InsertStatus = ListInsert_Dul(list, i, array[i]);
if (InsertStatus == OK) {
printf("向双链表第%d个位置插入元素%c成功!\n", i, array[i]);
} else {
printf("向双链表第%d个位置插入元素%c失败!\n", i, array[i]);
}
}
}
break;
case 9: {//输出链表元素
printLinkList(list);
}
break;
case 10: {//头插法创建双链表
//getchar();
DuLinkList L;
printf("请输入五个字符:\n");
CreateDLinkList_H(L, 5);
int length = GetLinkListLength(L);
printf("\n循环双链表的长度为:%d。 \n", length);
printf("循环双链表的元素为:");
printLinkList(L);
printf("\n");
}
break;
case 11: {//尾插法创建双链表
DuLinkList L;
printf("请输入五个字符:\n");
CreateDoubleList_R(L, 5);
int length = GetLinkListLength(L);
printf("\n循环双链表的长度为:%d。 \n", length);
printf("循环双链表的元素为:");
printLinkList(L);
printf("\n");
}
break;
default: {
printf("输入错误,无此功能,请检查输入:\n\n");
}
}
}
return 1;
}