循环单链表

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);                   //释放节点空间
        }
    }

运行结果

这里写图片描述

结语

链表的操作除了以上的追加,遍历,销毁外,还有插入,查找,删除,有序追加等操作,笔者在这里简单做个笔记,也给初学者一个初步了解,读者可以自己实现其他操作。感谢您的阅读^_^

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页