数据结构(单向循环链表)

发布于:2025-02-11 ⋅ 阅读:(23) ⋅ 点赞:(0)

循环单向链表

所谓的循环,指得是将链表末尾节点的后继指针指向头结点。比如,单向链表变成循环链表的示意 图如下所示:

在这里插入图片描述

循环链表的操作跟普通链表操作基本上是一致的,只要针对循环特性稍作修改即可。

  • sclist.h

     #ifndef __SCLIST_H
     #define __SCLIST_H
     typedef  int   DATA; 
    typedef struct node
     {
     DATA          
    data;
     struct node  *next;
     }NODE;
     // 链表创建
    int sclist_create(NODE**,DATA);
     // 链表数据添加
    int sclist_insert(NODE** head,DATA data);
     // 链表数据查询
    NODE* sclist_find(const NODE* head,DATA data);
     // 链表数据更新
    int sclist_update(const NODE* head,DATA old,DATA newdata);
     // 链表数据遍历
    void sclist_showAll(const NODE* head);
     // 链表数据删除
    #endif
    
  • sclist.c

 #include "sclist.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@function:   int sclist_create(NODE** head,DATA data);
 @berif:      创建单项链表
@argument:   head: 指向头指针变量的地址,用来接收首节点地址
             data: 存储在节点中的数据
@return :    成功返回 0
             失败返回 -1
 */
 int sclist_create(NODE** head,DATA data)
 {
    if(*head)
       return -1;
    NODE* p  = (NODE*)malloc(sizeof(NODE));
    if(!p)
    {
         return -1;
    }
    p -> data = data;
    p -> next = p;
    *head = p;
    return 0;
 }
 NODE* sclist_findtail(const NODE* head)
 {
    const NODE* p = head, *q = NULL;
    while(p)
    {
        q = p;
        p = p -> next;
        if(p == head)
            break;
    } 
    return (NODE*)q;
 }
 /*
 @function:   int sclist_insert(NODE** head,DATA data);
 @berif:      向链表节点值为pos的位置插入一个节点数据data
 @argument:   head: 指向头指针变量的地址
             data: 存储在新节点中的数据
@return :    成功返回 0
             失败返回 -1
 */
 int sclist_insert(NODE** head,DATA data)
     {
    NODE* tail = sclist_findtail(*head);    
    if(!tail)
      return sclist_create(head,data);           
    NODE *pNew = (NODE*)malloc(sizeof(NODE));
    if(!pNew)
      return  -1;
    pNew -> data = data;
    pNew -> next = *head;
    tail -> next = pNew;
 //    *head  = pNew;
    return 0;
 }
 /*
 @function:   NODE* sclist_find(const NODE* head,DATA data);
 @berif:      查找链表数据data
 @argument:   head: 指向头指针变量
             data: 待查找的数据
@return :    成功返回节点的地址
             失败返回NULL
 */
 NODE* sclist_find(const NODE* head,DATA data)
 {
    const NODE* p = head;
    
    while(p)
    {
         if(memcmp(&(p -> data),&data,sizeof(DATA)) == 0)
         {
             return (NODE*)p;
         }
         p = p -> next;
         if(p == head)
            break;
    }
    return NULL;
 }
 /*
 @function:   int sclist_update(const NODE* head,DATA old,DATA newdata);
 @berif:      更新链表数据old 为 newdata
 @argument:   head: 指向头指针变量
             old:  待更新的节点数据
             newdata: 更新后的节点数据
             @return :    成功返回  0
             失败返回  -1
 */
 int sclist_update(const NODE* head,DATA old,DATA newdata)
 {
     NODE* p = NULL;
     if(!(p = sclist_find(head,old)))
         return -1;
     p -> data = newdata;
     return 0;
 }
 /*
 @function:   void sclist_showAll(const NODE* head);
 @berif:      遍历链表数据
@argument:   head: 指向头指针变量
@return :    无
*/
 void sclist_showAll(const NODE* head)
 {
     const NODE*  p  = head;
    
     while(p)
     {
          printf("%d ",p -> data);
          p = p -> next;
          if(p == head)
             break; 
     }
     printf("\n");
 }
 /*
 @function:   int sclist_delete(NODE** head,DATA data);
 @berif:      删除链表中节点值为data的节点
@argument:   head: 指向头指针变量的地址
             data: 删除节点中的数据
@return :    成功返回 0
             失败返回 -1
 */
 int sclist_delete(NODE** head,DATA data)
 {
    NODE *p = *head, *q = NULL;
    if(!p)
              return -1;
   
    NODE* tail = sclist_findtail(*head);
    if(memcmp(&(p -> data),&data,sizeof(DATA)) == 0)
    {
        if(*head == tail)
        {
            *head = NULL;
            free(p);
            return 0;
        }
        tail -> next = (*head) -> next;
        *head = p -> next;
        free(p);
        return 0;
    }
    while(p)
    {
         if(memcmp(&(p -> data),&data,sizeof(DATA)) == 0)
         {
              q -> next = p -> next;
              free(p);
              return 0;
         }
         q  = p;
         p  = p -> next;
         if(p == *head)
            break;
    }
    return -1;
 }
 /*
 @function:   void sclist_destroy(NODE** head);
 @berif:      回收链表
@argument:   head: 指向头指针变量的地址
@return :    无
*/
 void sclist_destroy(NODE** head)
 {
   NODE* tail = sclist_findtail(*head);
   if(!tail)
   {
       return ;
   }
   tail -> next = NULL;    //将单向循环链表拆成单向链表
       NODE* p = *head, *q = NULL;
   
   while(p)
   {
        q = p;
        p = p -> next;
        free(q);
   }
   *head = NULL;
 }
  • sclist_main.c

     #include <stdio.h>
     #include <stdlib.h>
     #include "sclist.h"
     #define DELETE  
    extern int play_game(NODE** head,DATA num);
     int main(int argc,char** argv)
     {
        NODE*  head = NULL;
        if(sclist_create(&head,888) < 0) 
        {
            puts("create failed");
        return -1;
        }
        sclist_insert(&head,999);    
        sclist_insert(&head,222);    
        sclist_insert(&head,666);    
        sclist_insert(&head,777);    
        sclist_showAll(head);
        
        DATA   data ;
        while(0)
        {
      #ifdef DELETE
           printf("请输入要删除的数据:");
           scanf("%d",&data);
           if(data == -1)
              break;       
           if(sclist_delete(&head,data) < 0)
           {
               puts("删除失败,请重试");
                        continue;
           }
           sclist_showAll(head);
      #else
           NODE *pFind = NULL;
           DATA newdata = 512;
           printf("请输入要查找的数据:");
           scanf("%d",&data);
           if(data == -1)
              break;
          // if(!(pFind = slist_find(head,data)))
           if(slist_update(head,data,newdata) == -1)
           {
               puts("查找的数据不存在,请重试");
               continue;
           }
           //printf("查找数据:%d  内存地址:%p\n",pFind -> data, &(pFind -> data));
           slist_showAll(head);
      #endif
        }
        sclist_destroy(&head);
        puts("====销毁后====="); 
        sclist_showAll(head);
        
        puts("====PlayGame====="); 
        
        NODE*  pHead = NULL;
        for(int i = 1; i <= atoi(argv[1]); i++)
           sclist_insert(&pHead,i);
        sclist_showAll(pHead);
        DATA last = play_game(&pHead,5);
        printf("最后一个元素:%d\n",last);
        sclist_destroy(&pHead);
        puts("====销毁后====="); 
        sclist_showAll(pHead);
        return 0;
     }
    

这段代码使用了一个单向循环链表,实现了链表的创建、插入、删除、查找、更新、销毁等功能,并且还包含一个玩游戏的函数。

首先,在main函数中创建了一个链表,初始值为888。并且插入了几个元素(999, 222, 666, 777)。然后通过循环,可以选择删除某个元素或者查找某个元素进行更新。如果选择删除操作,会提示输入要删除的数据,并对链表进行删除操作。如果选择更新操作,会提示输入要查找的数据,并输入新的数据进行更新操作。在每次操作后,都会展示链表中的所有元素。

接下来,通过调用play_game函数来玩游戏。在play_game函数中,会根据给定的步长,不断遍历链表并删除指定步长的元素,直到链表只剩下最后一个元素为止。最后,输出最后一个元素的值。

最后,销毁链表并展示销毁后的链表。


网站公告

今日签到

点亮在社区的每一天
去签到