循环双链表的简单实现(C语言)
小结
双链表就像一群人手拉手站成一排,最旁边的两个人都有一个手空着。循环双链表就是一群人手拉手站成一圈,第一个人的手和最后一个人的手互相牵着。
双链表与循环双链表的插入删除等操作基本一致,表尾判断有所不同。双链表判断表尾为后继指向NULL,循环双链表判断表尾则看其后继是否指向头指针。
插入
结点后插
// 后插结点
bool InsertNextNode(DLNode *p, DLNode *s){
if(p == NULL && s == NULL) return true; // 数据非法性判断
p->next->prior = s; // p原后继结点的前继指向s
s->next = p->next; // s后继结点设为p的原后继结点
p->next = s; // p的后继结点设为s
s->prior = p; // s的前继结点设为p
return true;
}
结点前插
// 前插结点
bool InsertPriorNode(DLNode *p, DLNode *s){
// 在p结点前插入s结点
if(p == NULL && s == NULL) return true; // 数据非法性判断
s->prior = p->prior; // s的前继结点设为原p的前继结点
p->prior->next = s; // p的前继结点的后继指向s
s->next = p; // s的后继结点设为p
p->prior = s; // p的前继结点设为s
return true;
}
尾插法
// 尾插法
DLinkList List_TailInsert(DLinkList L){
ElemType e;
DLNode *p = L; // 声明一个结点,用于定位
scanf("%d", &e);
while(e != 9999){
while(p->next != L){
// 定位至表尾
p = p->next;
}
DLNode *s = (DLNode*)malloc(sizeof(DLNode)); // 声明一个新结点用于插入
s->data = e; // 存入数据
s->next = NULL;
s->prior = NULL;
InsertNextNode(p, s); // 调用后插结点函数实现插入
scanf("%d", &e);
}
return L;
}
头插法
// 头插法
DLinkList List_HeadInsert(DLinkList L){
ElemType e;
DLNode *p = L; // 声明一个结点,用于定位
scanf("%d", &e);
while(e != 9999){
if(p->next == L){
// 第一个结点特殊处理
DLNode *s = (DLNode*)malloc(sizeof(DLNode)); // 声明一个新结点用于插入
s->data = e; // 存入数据
L->next = s;
L->prior = s;
s->next = L;
s->prior = L;
}else{
DLNode *s = (DLNode*)malloc(sizeof(DLNode)); // 声明一个新结点用于插入
s->data = e; // 存入数据
s->next = NULL;
s->prior = NULL;
InsertPriorNode(L->next, s); // 调用前插结点函数,在第一个结点进行前插
}
scanf("%d", &e);
}
return L;
}
按位插入
// 按位插入
bool ListInsert(DLinkList L, int pos, ElemType e){
if(L == NULL || pos < 1) return false;
DLNode *p = L;
DLNode *s = (DLNode*)malloc(sizeof(DLNode)); // 创建一个新结点用于插入
s->data = e;
s->next = NULL;
s->prior = NULL;
while(--pos){
// 定位到插入位序的前一个结点
p = p->next;
}
if(InsertNextNode(p, s)){
//调用结点后插函数进行后插操作
return true;
}else false;
}
删除
结点后删
// 后删结点
bool DeleteNextNode(DLNode *p){
if(p == NULL) return true; // 数据合法性判