循环链表的优势是我们可以从任意结点出发访问数据,即我们把任意一个结点设置成root,然后从该结点出发。但是写成函数之后,为了通用,感觉在代码上循环链表和单链表没什么太大变化(可能是本人功力尚浅,求指点),个人感觉主要的变化有两点:
1.如果链表中只有一个结点,则头指针和尾指针相同,尾结点的指针域指向自己。
2.删除的是最后一个结点时,尾指针前移一个结点,新的尾结点的指针域指向头结点。
另外,这篇文中的代码虽然也是单链表,但是与上一篇单链表的基本操作中有点不同,上篇中的头结点的数据域是空的,这篇中的头结点的数据域有数据,具体看代码注释,之所以不同,纯属为了掌握链表的结构、熟悉操作、练习打字速度。。。而已。
上码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct LNode
{
void *data; // 这里设成指针型是因为 这里储存是要操作的数据的首地址,通过该数据域的地址(4个字节)操作它,提高效率,而无类型是为了通用
struct LNode *next;
}NODE;
typedef struct
{
NODE *head; //头指针 头指针是指向头结点的指针 此头结点数据域也存储信息
NODE *last; //尾指针
int length;
}CLList;
typedef struct students
{
char sno[5];
char name[21];
int age;
float score;
}STU;
STU s[6] = {
{"S001","lin wu",12,90},
{"S002","xiao ming",13,80},
{"S003","wang wu",11,100},
{"S004","xiao hong",14,24},
{"S005","zhang san",15,45},
{"S006","li xi",19,90}
};
CLList *CreateList(); // 创建链表
int AppendList(CLList *l, void *data, int size); // 在链表最后追加结点
int InsertList(CLList *l, int n, void *data, int size); // 在第 n 个结点之前插入一个结点
void PrintList(CLList *l, void (* printnode)(void *)); // 打印
int DeleteNode(CLList *l, int pos, void *e, int size); // 按位置删除,并返回所删结点数据域到 e
void PrintData(void *data)
{
STU *t = (STU *)data;
printf("%-5s %-10s %5d %5f\n",t->sno,t->name,t->age,t->score);
}
int main()
{
int i;
CLList *list = CreateList();
STU *e = (STU *)malloc(sizeof(STU));
for (i = 0; i < 4; ++i)
{
AppendList(list, &s[i], sizeof(s[i]));
}
PrintList(list, PrintData);
printf("\n\n");
InsertList(list, 3, &s[4], sizeof(s[4]));
PrintList(list, PrintData);
printf("\n\n");
DeleteNode(list, 1, e, sizeof(STU));
printf("所删结点的数据:\n");
printf("%-5s %-10s %5d %5f\n\n",e->sno,e->name,e->age,e->score);
PrintList(list, PrintData);
printf("\n\n");
return 0;
}
// 创建链表
CLList *CreateList()
{
CLList *l = (CLList *)malloc(sizeof(CLList));
if (NULL == l)
{
exit(0);
}
memset(l, 0, sizeof(CLList));
return l;
}
// 在链表最后追加结点
int AppendList(CLList *l, void *data, int size)
{
NODE *n = NULL;
if (NULL == l || NULL == data)
{
return 0;
}
n = (NODE *)malloc(sizeof(NODE));
if (NULL == n)
{
return 0;
}
n->data = malloc(size);
if (NULL == n->data)
{
free(n);
return 0;
}
memcpy(n->data, data, size);
if (NULL == l->head)
{
l->head = n;
}
else
{
l->last->next = n;
}
l->last = n;
l->last->next = l->head; // n->next = l->head;
l->length++;
return 1;
}
// 在第 n 个结点之前插入一个结点
int InsertList(CLList *l, int n, void *data, int size)
{
NODE *t = NULL, *p = NULL;
int i = 0;
if (NULL == l || NULL == data || n < 1 || n > l->length)
{
return 0;
}
t = (NODE *)malloc(sizeof(NODE));
if (NULL == n)
{
return 0;
}
t->data = malloc(size);
if (NULL == t->data)
{
free(t);
return 0;
}
memcpy(t->data, data, size);
p = l->head;
while (i < n - 2)
{
p= p->next;
++i;
}
t->next = p->next;
p->next = t;
l->length++;
return 1;
}
// 打印
void PrintList(CLList *l, void (* printnode)(void *))
{
NODE *p;
int i;
if (NULL == l || NULL == printnode)
{
return;
}
p = l->head;
for (i = 0; i < l->length ; ++i)
{
printnode(p->data);
p = p->next;
}
}
// 按位置删除,并返回所删结点数据域到 e
int DeleteNode(CLList *l, int pos, void *e, int size)
{
NODE *p = NULL, *q = NULL;
int i = 0;
if (NULL == l || pos < 1 || pos > l->length)
{
return 0;
}
p = l->head;
if (1 == pos)
{
q = p;
l->head = p->next;
}
else
{
while (i < pos - 2)
{
p = p->next;
++i;
}
q = p->next;
}
memcpy(e, q->data, size);
p->next = q->next;
l->length--;
free(q->data);
free(q);
return 1;
}