循环单链表的简单实现(C语言)
简述
循环单链表和单链表的不同之处在于——单链表的表尾指向空,而循环单链表的表尾指向头部第一个结点。因此,他们的边界处理会有些不同。循环单链表的好处在于——给出任一结点都能找到链表中的所有结点。而单链表只能找到该结点后面的结点,对于该节点前面的结点单链表是完全未知的。
插入
前插结点
// 前插结点
bool InsertpriorNode(CLNode *p, ElemType e){
if(p == NULL) return false; // 数据合法性判断
CLNode *s = (CLNode*)malloc(sizeof(CLNode)); // p为当前结点,s为欲插结点
if(s == NULL) return false; // 内存不足,分配失败
// 偷梁换柱法 将p存入s,再令p存入新数据.本质上还是后插
s->data = p->data; // p数据域存入s
s->next = p->next; // s下一结点指向p原后继结点
p->next = s; // p下一结点指向s
p->data = e; // p存入插入的数据
return true;
}
后插结点
// 后插结点
bool InsertNextNode(CLNode *p, ElemType e){
if(p == NULL) return false; // 数据合法性判断
CLNode *s = (CLNode*)malloc(sizeof(CLNode));
if((s) == NULL) return false; // 内存不足,分配失败
s->data = e; // 存入数据域
s->next = p->next; // s联结p原后继
p->next = s; // p联结s
return true;
}
头插法
// 头插法
CLinkList List_HeadInsert(CLinkList L){
ElemType e;
scanf("%d", &e);
while(e != 9999){
// 第一个结点要特殊处理
if(L->next == L){
// 链表为空则创建一个新结点
CLNode *p = (CLNode*)malloc(sizeof(CLNode));
L->next = p; // 令新结点成为头结点的后继结点
p->next = L;
p->data = e;
}else{
InsertpriorNode(L->next, e); // 进行结点后插操作
}
scanf("%d", &e);
}
return L;
}
尾插法
// 尾插法
CLinkList List_TailInsert(CLinkList L){
ElemType e;
scanf("%d", &e);
while(e != 9999){
CLNode *p = (CLNode*)malloc(sizeof(CLNode));
p = L;
while(p->next != L){
// 第一个结点进行特殊处理
if(L->next == L){
// 头结点为空则创建一个新结点
CLNode *p = (CLNode*)malloc(sizeof(CLNode));
L->next = p; // L的下一结点指向p
p->next = L; // p的下一结点指向L
p->data = e; // p存入数据
}
p = p->next; // 移到下一个结点
}
InsertNextNode(p, e); // 调用后插结点函数进行后插操作
scanf("%d", &e);
}
return L;
}
按位插入
// 按位插入
bool ListInsert(CLinkList *L, int pos, ElemType e){
CLNode *p = *L;
int i = 0;
for(i; i < pos-1; i++){
// 定位到欲插入位序的前继结点
p = p->next;
}
if(InsertNextNode(p, e)){
// 调用后插结点函数进行后插操作并判断操作是否成功
return true;
}else false;
}
删除
结点后删
// 结点后删
bool DeleteNode(CLNode *p){
// 删除p结点的后继结点
if(p == NULL) return false; // 数据非法性判断
CLNode *s = p->next; // s为p的后继结点
p->next = s->next; // p指向s的后继结点
free(s