C语言学到数据结构那么免不了要遇到链表的问题,笔者在初学时也是容易把指针混淆,双链表始终是循环最为方便,单链表也可以实现循环,本文采用了带头结点的尾部追加方式,对循环单链表的简单初始化过程做一下总结。
原理
单链表的原理比较简单,每个节点存放指向下一节点的指针,最后节点指向空指针NULL:
头节点指针head->1->2->3->4->5->NULL
如果是循环单链表,则最后一个节点的指针指向第一个节点:
头节点指针head->1->2->3->4->5->1->2->3…
过程
1.链表结构体定义;
2.申请新节点空间;
3.新节点数据域赋值;
4.新节点在链表中尾部追加;
5.遍历链表 (即访问节点数据);
6.销毁链表(释放全部节点空间)。
代码
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>
//链表定义
typedef struct node{
struct node *next;
int data;
}Node_t;
void appendTail(Node_t *h,int num);
void travelList(const Node_t *h);
void destroyList(Node_t *h);
int main(void)
{
//头指针初始化
Node_t head={.next=NULL};
int num;
printf("input number -1 over:\n");
//动态建立链表,输入数字,如果输入为-1停止追加
while(1)
{
scanf("%d",&num);
if(num==-1) break;
appendTail(&head,num);
}
travelList(&head);
destroyList(&head);
return 0;
}
//尾部追加
void appendTail(Node_t *h,int num)
{
Node_t *i,*one;
//为新节点分配节点空间
one=malloc(sizeof(Node_t));
assert(one!=NULL); //断言,判断是否为空
one->data=num; //数据域赋值
one->next=NULL; //尾部指向空指针
//若为空链表,将节点挂入链表
if(h->next==NULL)
{
h->next=one;
one->next=h->next;
}
//若链表不为空,则依次挂入链表
else
{
//找到尾部节点
for(i=h->next;i->next!=h->next;i=i->next)
{
;
}
i->next=one; //将尾部节点指向新节点
one->next=h->next; //新节点指向第一个节点
}
}
//遍历链表,打印20个节点的数据
void travelList(const Node_t *h)
{
Node_t *i;
if(h->next==NULL)
{
printf("Empty List.\n"); //链表为空
return;
}
int j;
for(j=0,i=h->next;j<20;i=i->next,j++)
{
printf("%d ",i->data);
if(i->next==h->next)
{
if(j==19) getchar(); //消除遍历结束时的回车符
else
{
putchar('\n'); //循环一次用回车符分隔
}
}
}
putchar('\n');
}
//销毁链表
void destroyList(Node_t *h)
{
Node_t *i;
for(i=h->next;i!=h->next;i=i->next)
{
free(i); //释放节点空间
}
}
运行结果
结语
链表的操作除了以上的追加,遍历,销毁外,还有插入,查找,删除,有序追加等操作,笔者在这里简单做个笔记,也给初学者一个初步了解,读者可以自己实现其他操作。感谢您的阅读^_^