引入

我们讲了顺序存储结构、单链表、静态链表,今天我们学习一种新的链表,单循环链表,单循环链表很简单,其实就是在单链表的基础上,将头尾相连,形成一个单向环装循环。

单循环链表

我们知道,单链表非常有趣,虽然不连续,但却根据指针一个连着一个,但是单链表有一个问题,我们如果不从头结点出发,就无法访问所有结点。
解决方法也非常简单,就是把链表终端结点得指针由 NULL 改成指向头结点。也就是链表最后一个结点存储得指针为头结点得指针,也就是原来 head 存储的地址。
既然head 和 最后一个结点 都指向头结点,那么我们就称这种头尾相接得单链表位单循环链表

单循环链表的特点

既然头尾相接,那么单循环链表有新增了下面几种特性

  • head 指向头结点,尾部也指向头结点
  • 判断空表得时候,只要头结点和头部指向得内容都是该结点本身,那么这个表就是空表。
  • 头结点即尾部,头结点指向头结点,head 指向头结点
  • 原来是 head->next 是否为 NULL,是就为空表
  • 现在是 head 是否等于 head->next,即头结点指针指向它自己
  • 我们把最后一个结点得指针称为 rear

单循环链表

我们先生成一个5结点的链表,然后向后插入一位,看看,还是不是单向循环链表。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LEN sizeof(struct Student)
#define MAXSIZE 5

struct Student{
    int num;
    float score;
    struct Student *next;
};

struct Student *stu_init(){
   srand((time(0)));
    struct Student *a,*b,*head;
    a=b=(struct Student *)malloc(LEN);
    int n=0;
   while(n<=MAXSIZE){
       a=(struct Student *)malloc(LEN);
       a->num=n;
       a->score=rand()%100+1;
        if(n==1){
            head=a;
            b=a;
        }else{
            b->next=a;
            b=a;
        }
       n=n+1;
   }
    b->next=head;
    return head;
}

void stu_printf(struct Student *stu_p){
    struct Student *stu,*head;
    stu=head=stu_p;
   while(stu->next!=head){
        printf("%d号%3.1f分\n",stu->num,stu->score);
        stu=stu->next;
   }
}

void stu_insert(struct Student *stu_p , int num , float data){
    struct Student *target , *temp;
    target=stu_p;
    if(num==1){
        target->num=num;
        target->score=data;
        target->next=stu_p;
    }else{
        for(int l=0;l<num-1;l++){
            target=target->next;
        }
        temp=(struct Student *)malloc(LEN);
        temp->score=data;
        temp->num=num;
        temp->next=target->next;
        target->next=temp;
    }
    printf("%d\n",temp->next->num);
    
}

int main(){
    struct Student *stu;
    stu=stu_init();
    stu_insert(stu, 5, 11.1);
    stu_printf(stu);
}

输出
1
1号65.0分
2号25.0分
3号66.0分
4号12.0分
5号47.0分

**初始化:**初始化完成后,一定要记得把首尾相连,否则构不成循环。

**插入:**插入的时候一定要记得沿着链表来找,找到前一个,然后将其指针域赋值给插入得结点,然后将指针域指向插入的结点的地址。

**判断:**上面的1输出得是printf("%d\n",temp->next->num); 也就是最后插入的这个结点的下一结点得编号,如果是循环链表的话,那么就应该是1才对,因为又会指向头结点。

尾巴

这是我的个人学习笔记,主要是应付考研复习使用,充斥着一些吐槽和个人观点,并不严谨,欢迎大家参考、指正。