引入

我们学习了循环链表的基本操作,也学习了一个有趣的约瑟夫问题,我们之前说过有头指针也有尾指针,头指针指向头结点,尾指针指向尾结点。那么尾指针有哪些有趣的用法呢?

单循环链表的问题

我们知道,在单向循环链表中,我们有头指针

  • O ( 1 ) 的时间去找到第一个结点,因为 next 就是头结点
  • O ( n ) 的时间去找最后一个结点,因为第 n 个才是尾结点

如何在访问头结点和尾结点得时候,都是O( 1 )时间复杂度呢?

尾指针应运而生!

  • 尾指针指向的是尾节点
  • 而尾节点得下一个就是头结点

所以尾指针访问头结点和尾节点的时间都是 O ( 1 ) 。
撒花~~~

尾指针

我们看到这张图

  • 尾指针的名称为 rear
  • rear 指向得是终端结点的地址
  • rear 的 next 元素为头结点
  • **特点:**特点就是可以灵活的操作头结点和尾结点

一个例题

创建两个单循环链表,将其合并成一个循环链表。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LEN sizeof(struct Student)
#define NUM 20
struct Student{
    int num;
    struct Student *next;
};

struct Student *create(int min,int max){
    if(min>=max){
        printf("输入错误!");
        return 1;
    }
    struct Student *a,*b,*head;
    int i=min;
    while(min<=max){
        a=(struct Student *)malloc(LEN);
        if(min==i){
            head=a;
        }else{
            b->next=a;
        }
        a->num=min++;
        b=a;
    }
    b->next=head;
    head=b;
    return head;
}

void stu_print(struct Student *stu_p){
    struct Student *head;
    head=stu_p;
    do{
        printf("%d\n",stu_p->next->num);
    }while((stu_p=stu_p->next)!=head);
}

struct Student *stu_mix(struct Student *stu_a,struct Student *stu_b){
    struct Student *mix_a;
    mix_a=stu_a->next;  //保存 a 的头结点位置
    stu_a->next=stu_b->next->next; // A的表尾存储得地址 改为 B头结点存储的位置,A的尾巴连接到B的头。A指向得是头结点指向的
    stu_b->next=mix_a;  // B的表尾存储的地址 改为 A 头结点得地址
    return stu_b;
}

int main(){
    struct Student *stu_a,*stu_b;
    stu_a=create(1,20);
    stu_b=create(21,40);
    stu_print(stu_mix(stu_a,stu_b));
    return 0;
}

合并两个单循环链表有三个步骤

  • 先把 A 的头结点的位置存下来
  • A 的尾巴指向 B 的头结点
  • B 得尾巴指向刚才存下在的 A 的头结点

尾巴

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