结构-循环链表的实现

3.循环链表的实现

3.1定义一个结点
typedef struct list{
    int data;
    struct list *next;
}list;
//data为存储的数据,next指针为指向下一个结点
//和单链表的结点一样。
3.2初始化一个结点
//初始结点
list *initlist(){
    list *head=(list*)malloc(sizeof(list));
    if(head==NULL){
        printf("创建失败,退出程序");
        exit(0);
    }else{
        head->next=NULL;
        return head;
    }
}
//由于循环链表的特殊性,已经为之后的方便使用,一个初始化好的循环链表的头结点的next需要指向自身。
//所以上面的操作是不完整的,在具体使用的时候,我们还需要在主函数里加上如下操作:
在主函数重调用可以是这样
    //////////初始化头结点//////////////
    list *head=initlist();
    head->next=head;
3.3创建循环链表

注意是’创建---插入数据‘,这说明一个循环链表的创建是在数据逐个的插入中完成的。

但这个插入还和插入操作的插入不一样,那个插入是在目标位置,而这个插入是在表的末尾(虽然循环链表没有什么开始结束之类的,但名义上的head和end还是有的)

//创建——插入数据
int insert_list(list *head){
    int data;   //插入的数据类型
    printf("请输入要插入的元素:");
    scanf("%d",&data);
  
    list *node=initlist();
    node->data=data;
    //初始化一个新的结点,准备进行链接
  
    if(head!=NULL){
        list *p=head;
        //找到最后一个数据
        while(p->next!=head){//①
            p=p->next;
        }
        p->next=node;
        node->next=head;
        return 1;
    }else{
        printf("头结点已无元素\n");
        return 0;
    }
  
}
//①前面的单链表和双向链表通过NULL找到链表的结尾,而循环链表通过链表头next的地址head找到链表名义上的结尾。循环链表也正是通过这种方法实现在链表所谓结尾的插入。
3.4插入新结点
//插入元素
list *insert_list(list *head,int pos,int data){
    //三个参数分别是链表,位置,参数
    list *node=initlist();  //新建结点
    list *p=head;       //p表示新的链表
    list *t;
    t=p;
    node->data=data;
    if(head!=NULL){
        for(int i=1;i<pos;i++){
            t=t->next;  //走到需要插入的位置处
        }
        node->next=t->next;
        t->next=node;
        return p;
    }
    return p;
}
3.5删除结点
//删除元素
int delete_list(list *head) {
    if(head == NULL) {
        printf("链表为空!\n");
        return 0;
    }
    //建立临时结点存储头结点信息(目的为了找到退出点)
    //如果不这么建立的化需要使用一个数据进行计数标记,计数达到链表长度时自动退出
    //循环链表当找到最后一个元素的时候会自动指向头元素,这是我们不想让他发生的------①
    list *temp = head;        //此时temp指向头结点  
    list *ptr = head->next;	  //此时ptr指向头结点的下一个节点
  
    int del;
    printf("请输入你要删除的元素:");
    scanf("%d",&del);
  
    while(ptr != head) {
        if(ptr->data == del) {		
            if(ptr->next == head) {    //判断删除节点是否为尾结点
                temp->next = head;
                free(ptr);
                return 1;				//跳出循环
            }
            temp->next = ptr->next;    //核心删除操作代码
            free(ptr);					//说明了ptr是目标删除结点。
            //printf("元素删除成功!\n");
            return 1;
        }
        temp = temp->next;
        ptr = ptr->next;	//标准的遍历操作。
    }c
    printf("没有找到要删除的元素\n");
    return 0;
}
//观察前面的链表就能明白是什么意思。前面链表用while和NULL判断循环并退出,而循环列表没有NULL。为了避免死循环,我们需要采用其他策略——例如利用链表头的地址当作循环条件判断跳出循环,当然也可以用代码注释中说的计数器来判断终止循环。
3.6循环链表的遍历
//遍历元素
int display(list *head) {
    if(head != NULL) {
        list *p  = head;
        //遍历头节点到,最后一个数据
        while(p->next != head ) {
            printf("%d   ",p->next->data);
            p = p->next;
        }
        printf("\n");   //习惯性换行 ( o=^•ェ•)o ┏━┓
        //把最后一个节点赋新的节点过去
        return 1;
    } else {
        printf("头结点为空!\n");
        return 0;
    }
}
//关键还是找到合适的终止循环条件。目前已知的就是计数器和链表头地址。
3.7完整的循环链表代码
 #include<stdio.h>
#include<stdlib.h>
typedef struct list{
    int data;
    struct list *next;
}list;
//data为存储的数据,next指针为指向下一个结点
 
//初始结点
list *initlist(){
    list *head=(list*)malloc(sizeof(list));
    if(head==NULL){
        printf("创建失败,退出程序");
        exit(0);
    }else{
        head->next=NULL;
        return head;
    }
}
 
//创建--插入数据
int create_list(list *head){
    int data;   //插入的数据类型
    printf("请输入要插入的元素:");
    scanf("%d",&data);
 
    list *node=initlist();
    node->data=data;
    //初始化一个新的结点,准备进行链接
 
    if(head!=NULL){
        list *p=head;
        //找到最后一个数据
        while(p->next!=head){
            p=p->next;
        }
        p->next=node;
        node->next=head;
        return 1;
    }else{
        printf("头结点已无元素\n");
        return 0;
    }
 
}
 
//插入元素
list *insert_list(list *head,int pos,int data){
    //三个参数分别是链表,位置,参数
    list *node=initlist();  //新建结点
    list *p=head;       //p表示新的链表
    list *t;
    t=p;
    node->data=data;
    if(head!=NULL){
        for(int i=1;i<=pos;i++){
            t=t->next;
        }
        node->next=t->next;
        t->next=node;
        return p;
    }
    return p;
}
 
//删除元素
int delete_list(list *head) {
    if(head == NULL) {
        printf("链表为空!\n");
        return 0;
    }
    //建立零时结点存储头结点信息(目的为了找到退出点)
    //如果不这么建立的化需要使用一个数据进行计数标记,计数达到链表长度时自动退出
    //循环链表当找到最后一个元素的时候会自动指向头元素,这是我们不想让他发生的
    list *temp = head;          
    list *ptr = head->next;
 
    int del;
    printf("请输入你要删除的元素:");
    scanf("%d",&del);
 
    while(ptr != head) {
        if(ptr->data == del) {
            if(ptr->next == head) { //循环结束的条件换成ptr->next == head
                temp->next = head;
                free(ptr);
                return 1;
            }
            temp->next = ptr->next;
            free(ptr);
            //printf("元素删除成功!\n");
            return 1;
        }
        temp = temp->next;
        ptr = ptr->next;
    }
    printf("没有找到要删除的元素\n");
    return 0;
}
 
 
//遍历元素
int display(list *head) {
    if(head != NULL) {
        list *p  = head;
        //遍历头节点到,最后一个数据
        while(p->next != head ) {
            printf("%d   ",p->next->data);
            p = p->next;
        }
        printf("\n");   //习惯性换行 ( o=^•ェ•)o ┏━┓
        //把最后一个节点赋新的节点过去
        return 1;
    } else {
        printf("头结点为空!\n");
        return 0;
    }
}
 
int main(){
    //////////初始化头结点//////////////
    list *head=initlist();
    head->next=head;
    ////////通过插入元素完善链表/////////
    for(int i=0;i<5;i++){   //只是演示使用,不具体提供输入
        create_list(head);
    }
    display(head);
    ////////////插入元素////////////////
    head=insert_list(head,1,10);
    display(head);
    ////////////删除元素////////////////
    delete_list(head);
    display(head);
    return 0;
}
posted @ 2021-08-25 10:15  hyy233  阅读(185)  评论(0)    收藏  举报