完成单链表的后续操作(实现一个无头无环的单链表)

         之前我们完成了顺序表的一些操作,今天我们就来说一说链表。

        链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。它可以根据需要开辟内存单元。链表有一个“头指针”变量,以head表示,它存放一个地址。该地址指向一个元素。链表中每一个元素称为“结点”,每个结点都应包括两个部分:一为用户需要用的实际数据,二为下一个结点的地址。因此,head指向第一个元素:第一个元素又指向第二个元素;……,直到最后一个元素,该元素不再指向其它元素,它称为“表尾”,它的地址部分放一个“NULL”(表示“空地址”),链表到此结束。

        链表分为很多种,有头结点,无头结点,有环,无环,单链表,双链表,排列组合就是8种。即有头有环单链表,有头无环单链表,有头有环双链表,有头无环双链表,无头有环单链表,无头无环单链表,无头有环双链表,无头无环双链表。今天我们要实现的是有头结点有环的单链表。

        说完链表的种类我们来说一说链表的内容,链表是由结构体和指针构成的,我们定义一个名为LinkNode的结构体,里面存一个数据,一个指向下一个结点的指针。

        下面我们就来实现这个无头无环的单链表的后续操作。


        LinkList.h

        

 #pragma once
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
 typedef char LinkType;  //定义链表中的结构为char类型
 typedef struct LinkNode  //定义一个结构体,里面存一个数据,一个指向下一个结点指针。
  {
      LinkType data;
      struct LinkNode *next;
  }LinkNode;
 void LinkListInit(LinkNode **head); //初始化函数
 
 LinkNode* LinkCreatNewNode(LinkType value); //创建一个新的结点
 
 void LinkListPushBack(LinkNode **head,LinkType value);  //尾插
 
 void LinkListPopBack(LinkNode **head);  //尾删
 
 void LinkListPushFront(LinkNode **head,LinkType value); //头插
 
 void LinkListPopFront(LinkNode **head); //头删
 
 LinkNode* LinkListFind(LinkNode *head,LinkType to_find);    //查找链表中的元素所在的位置
  
 void LinkListInsert_before(LinkNode **head,LinkNode *pos,LinkType value);   //在pos之前插入一个元素
 
 void LinkListInsert_before2(LinkNode **head,LinkNode *pos,LinkType value);  //在pos之前插入一个元素
  
 void LinkListInsert_After(LinkNode **head,LinkNode *pos,LinkType value);    //在pos之后插入一个元素
 
 void LinkListErase(LinkNode **head,LinkNode *pos);  //删除指定位置的元素
  
 void LinkListRemove(LinkNode **head,LinkType to_delete);    //删除指定值的元素
  
 void LinkListRemoveAll(LinkNode **head,LinkType to_delete); //删除所有指定值的元素
 
 int LinkListEmpty(LinkNode *head);  //判断链表是否为空
  
 size_t LinkListSize(LinkNode *head);    //求链表的长度
 
 void LinkListReversePrint(LinkNode *head);  //打印逆序链表
                                                       

        

        LinkList.c

     

扫描二维码关注公众号,回复: 1169233 查看本文章
#include <stdio.h>
#include <stdlib.h>
#include "LinkList.h"

LinkNode* CreatNewNode(LinkType value)
  {
    LinkNode* NewNode = (LinkNode*)(malloc(sizeof(LinkNode)));
    NewNode->data = value;
    NewNode->next = NULL;
    return NewNode;
 }
void LinkListPrint(LinkNode* head)  //打印函数
  {
     if(head == NULL)
     {
         printf("空链表\n");
         return;
     }
     {
         LinkNode* cur = head;
         while(cur)
         {
             printf("[%c|%p]",cur->data,cur);
             cur = cur->next;
         }
         printf("\n");
     }
  }
 
void DestoryNode(LinkNode** Delete) //销毁函数
  {
     free(*Delete);
 }
 
void LinkListInit(LinkNode** head)  //初始化函数
 {
     if(head == NULL)    //非法输入
     {
         printf("非法输入\n");
         return;
     }
     if(*head == NULL)   //空链表
     {
         printf("空链表\n");
         return;
     }
     *head = NULL;
 }
void Swap(LinkType *a,LinkType *b)	//交换函数
 {
     LinkType tmp = *a;
     *a = *b;
     *b = tmp;
 }
void LinkListPushBack(LinkNode** head,LinkType value)   //尾插函数
 {
     if(head == NULL)    //非法输入
     {
         printf("非法输入\n");
         return;
     }
     if(*head == NULL)   //空链表
     {
         (*head) = CreatNewNode(value);  //如果为空链表,创建一个新结点,头指针指向这个新结点
     }
     else
     {
         LinkNode* begin = *head;    //如果链表不为空,头指针指向begin这个结点
         while(begin->next)  //遍历一遍链表
         {
             begin = begin->next;
         }
         begin->next = CreatNewNode(value);  //遍历完链表后,在begin的下一个结点处创建一个新结点,实现尾插
     }
 }
void LinkListPopBack(LinkNode** head)   //尾删函数
 {
     if(head == NULL)    //非法输入
     {
         printf("非法输入\n");
         return;
 
     }
     if(*head == NULL)   //空链表
     {
         printf("空链表,无法删除\n");
         return;
     }
     LinkNode* pop = *head;  //如果不为空链表,头指针指向pop结点
     while(pop->next->next)  //遍历链表,直到pop的下一个位置的下一个位置为空退出循环
                             //这里说一下,pop->next->next为空,则pop->next指向的就是最后一个结点的位置
     {
         pop = pop->next;
     }
     LinkNode* Delete = pop->next;   //所以pop->next指向的结点就是要删除的那个结点,定义那个结点为Delete结点,也就是最后一个结点
     pop->next = NULL;               //现在让pop->next指向空
     DestoryNode(&Delete);           //销毁Delete结点
 }
void LinkListPushFront(LinkNode** head,LinkType value)  //头插
 {
     if(head == NULL)    //非法输入
     {
        printf("非法输入\n");
         return;
     }
     if(*head == NULL)
     {
         LinkNode* NewNode  = CreatNewNode(value);   //链表为空时,创建一个新结点
         *(head) = NewNode;                          //头指针指向新结点
    }
     else
     {
        LinkNode* NewNode = CreatNewNode(value);    //链表不为空时,也创建一个新结点
        NewNode->next = *head;  //让头指针指向新结点的下一个结点,所以现在所说的下一个结点就是原来的第一个结点,
                                //那么现在的新结点就是第一个结点的位置
        *head = NewNode;        //头指针再指向新结点
     }
 }
void LinkListPopFront(LinkNode** head)  //头删
 {
     if(head == NULL)    //非法输入
     {
         printf("非法输入\n");
         return;
     }
     if(*head == NULL)   //空链表
     {
         printf("空链表,无法删除\n");
         return;
     }
     else
     {
         LinkNode* Delete = (*head);     //定义一个Delete结点,头指针指向Delete结点,Delete就是第一个结点,也就是要删除的结点
         (*head) = (*head)->next;        //头指针指向头指针的next
         DestoryNode(&Delete);           //销毁Delete结点
     }
 }
 LinkNode* LinkListFind(LinkNode* head,LinkType to_find)    //根据元素值查找结点
 {
     if(head == NULL)    //空链表
     {
         printf("空链表\n");
         return;
     }
 
     else
     {
         LinkNode* cur = head;
         while(cur)  //遍历链表
         {
             if(cur->data == to_find)
             {
                 return cur; //当cur结点的元素等于我们要寻找的元素时,返回cur结点的地址
             }
             cur = cur->next;
         }
         return ;
     }
 
 }
 
 
 
void LinkListInsert_before(LinkNode** head, LinkNode* pos,LinkType value)    //在任意元素之前插入,需要遍历链表
 {
     if(head == NULL)
     {
         printf("非法输入\n");
         return;
     }
     if(*head == NULL)
     {
         printf("空链表\n");
         return;
     }
     if(pos == NULL)
     {
         return;
     }
     if(pos == (*head))  // =是赋值,==是判断,当pos的位置是头指针所指向的位置时
     {
         LinkNode* NewNode = CreatNewNode(value);    //创建一个新结点
         NewNode->next = *head;  //新结点的next指向头指针指向的结点
         *head = NewNode;    //让头指针指向新结点
     }
     else    //当pos的位置不是头指针所指向的位置时
     {
 
         LinkNode* cur = *head;  //头指针指向cur结点
         while((cur->next)!=pos) //遍历链表,直到cur的next指向pos位置的结点时
         {
             cur = cur->next;
         }
         LinkNode* NewNode = CreatNewNode(value);    //创建一个新结点
         NewNode->next = pos;    //结点的next指向pos位置的结点
         cur->next = NewNode;    //cur的next指向NewNode结点
     }
 
 }
void LinkListInsert_before2(LinkNode** head,LinkNode* pos,LinkType value)    //在任意元素之前插入,不需要遍历链表
 {
     if(head == NULL)
     {
         printf("非法输入\n");
         return;
     }
     if(*head == NULL)
     {
         printf("空链表\n");
         return;
     }
 
     if(pos == (*head))  // =是赋值,==是判断,当pos的位置是头指针所指向的位置时
     {
         LinkNode* NewNode = CreatNewNode(value);    //创建一个新结点
         NewNode->next = *head;  //新结点的next指向头指针指向的结点
         *head = NewNode;    //让头指针指向新结点
     }
     else
     {
         LinkNode* NewNode = CreatNewNode(value);
         LinkNode* afterNode = pos->next;
         pos->next = NewNode;
         NewNode->next = afterNode;
         Swap(&NewNode->data,&pos->data);
     }
 }
 
 
 
void LinkListInser_after(LinkNode** head,LinkNode* pos,LinkType value)    //在任意元素之后插入
 {
     if(head == NULL)    //非法输入
     {
         printf("非法输入\n");
         return;
     }
     if(*head == NULL)   //空链表
     {
         printf("空链表\n");
 
     }
     if(pos == NULL)
     {
         return;
     }
     LinkNode* cur = *head;  //头指针指向cur结点
     while(cur)  //遍历链表
     {
         if(cur == pos)  //当cur等于pos位置的结点时
         {
             LinkNode* afterNode = cur->next;    //定义一个afterNode结点,让cur的next指向afterNode结点
             cur->next = NewNode;    //现在让cur的next指向NewNode结点
             NewNode->next = afterNode;  //NewNode的next指向afterNode结点
         }
         cur = cur->next;
     }
 }
 
void LinkListErase(LinkNode** head,LinkNode* pos)    //删除任意位置元素
 {
     if(head == NULL)    //非法输入
     {
         printf("非法输入\n");
         return;
     }
     if(*head == NULL)   //空链表
     {
         printf("空链表\n");
         return;
     }
     if(pos == NULL)
     {
         return;
     }
     LinkNode* cur = *head;
     while(cur)  //遍历链表
     {
         if(cur->next == pos)    //直到cur的next指向pos位置的结点
         {
             cur->next = pos->next;  //cur的next指向pos的next
             DestoryNode(&pos);  //销毁pos位置的结点

         }
         cur = cur->next;
     }
 }
 void LinkListRemove(LinkNode** head,LinkType delete)    //删除链表中第一个指定元素
 {
     if(head == NULL)    //非法输入
     {
         printf("非法输入\n");
         return;
     }
     if(*head == NULL)   //空链表
     {
         printf("空链表\n");
         return;
     }
     LinkNode* cur = *head;  //头指针指向cur结点
     LinkListErase(head,(LinkListFind(*head,delete)));   //调用LinkListFind函数找到delete元素的结点地址,
                                                         //再用LinkListErase函数删除delete元素的结点
 
 }
void LinkListRemoveAll(LinkNode** head,LinkType delete)    //删除所有指定元素
 {
     if(head == NULL)    //非法输入
     {
         printf("非法输入\n");
         return;
     }
     if(*head == NULL)   //空链表
     {
         printf("空链表\n");
         return;
     }
     LinkNode* cur = *head;  //头指针指向cur结点
     while(cur)  //当cur不为空时,循环
     {
         LinkListErase(head,(LinkListFind(*head,delete)));   //调用LinkListFind函数找到delete元素的结点地址
                                                             //再用LinkListErase函数删除delete元素的结点
         cur = cur->next;    //遍历链表
     }
 }
int LinkListEmpty(LinkNode* head)    //判断链表是否为空
 {
     if(head == NULL)
    {
         printf("空链表\n"); //空链表返回1
         return 1;
     }
     else
     {
 
         printf("链表不为空\n"); //非空链表返回0
         return 0;
     }
 }
size_t LinkListSize(LinkNode* head)    //计算链表长度
 {
     if(head == NULL)
     {
         printf("空链表\n"); //空链表
         return;
     }
     size_t count;
     LinkNode* cur = head;
     while(cur)
     {
         count++;
         cur = cur->next;    //遍历链表,count++
     }
     return count;
 }
 
void LinkListReverse(LinkNode* head)    //链表逆序
 {
     if(head == NULL)
     {
 
         return;
     }
     else
     {
         LinkListReverse(head->next);    //这里利用递归思想
         printf("[%c|%p]",head->data,head);
     }
 }
     //测试函数 test.c
 void test_LinkListPushBack()    //尾插测试函数
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******尾插*******\n");
     LinkListPushBack(&pnod,'a');    //  调用尾插插入四个元素
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPushBack(&pnod,'d');
     LinkListPrint(pnod);
 }
 void test_LinkListPopBack() //尾删测试函数
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******尾删*******\n");
     LinkListPushBack(&pnod,'a');    //先调用尾插插入两个元素
     LinkListPushBack(&pnod,'b');
     LinkListPrint(pnod);
     LinkListPopBack(&pnod); //调用尾删删除最后一个元素
     LinkListPrint(pnod);
 }
 void test_LinkListPushFront()   //头插测试函数
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******头插*******\n");
     LinkListPushBack(&pnod,'a');    //调用头插插入三个元素
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPrint(pnod);
 }
 void test_LinkListPopFront()    //头删测试函数
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******头删*******\n");
     LinkListPushBack(&pnod,'a');    //调用头插插入两个元素
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPrint(pnod);
     LinkListPopFront(&pnod);    //调用头删删除第一个元素
     LinkListPrint(pnod);
 }
 void test_LinkListFind()
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******根据元素值找结点*******\n");
     LinkListPushBack(&pnod,'a');    //调用头插插入三个元素
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPrint(pnod);
     LinkNode* i =   LinkListFind(pnod,'a'); //找到a的结点地址
     printf("找到的结点地址为:%p\n",i);
 }
 
 void test_LinkListInsert_before()
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******任意位置之前插入元素*******\n");
     LinkListPushBack(&pnod,'a');    //  调用尾插插入四个元素
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPushBack(&pnod,'d');
     LinkListPrint(pnod);
     LinkListInsert_before(&pnod,(LinkListFind(pnod,'b')),'m');  //在b之前插入m
     LinkListPrint(pnod);
 }
 void test_LinkListInsert_before2()
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******任意位置之前插入元素2*******\n");
     LinkListPushBack(&pnod,'a');    //  调用尾插插入四个元素
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPushBack(&pnod,'d');
     LinkListPrint(pnod);
     LinkListInsert_before2(&pnod,(LinkListFind(pnod,'b')),'m'); //在b之前插入m
     LinkListPrint(pnod);
 }
 
 void test_LinkListInsert_after()
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******任意位置之后插入元素*******\n");
     LinkListPushBack(&pnod,'a');    //  调用尾插插入四个元素
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPushBack(&pnod,'d');
 LinkListPrint(pnod);
     LinkListInser_after(&pnod,(LinkListFind(pnod,'b')),'m');    //在b之后插入m
     LinkListPrint(pnod);
 }
 void test_LinkListErase()
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******根据结点位置删除任意位置元素*******\n");
     LinkListPushBack(&pnod,'a');    //调用尾插插入三个元素
     LinkListPushBack(&pnod,'b');
                                          
     LinkListPushBack(&pnod,'c');
     LinkListPrint(pnod);
     LinkListErase(&pnod,(LinkListFind(pnod,'b')));  //删除b元素
     LinkListPrint(pnod);
 }
 void test_LinkListRemove()
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******根据元素值删除任意元素*******\n");
     LinkListPushBack(&pnod,'a');
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPrint(pnod);
     LinkListRemove(&pnod,'b');  //删除b元素
     LinkListPrint(pnod);
 }
 void test_LinkListRemoveAll()
 {
 
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******根据元素值删除任意元素*******\n");
     LinkListPushBack(&pnod,'a');
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPrint(pnod);
     LinkListRemoveAll(&pnod,'b');   //删除所有的b元素
     LinkListPrint(pnod);
 }
 void test_LinkListEmpty()
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     LinkListPushBack(&pnod,'a');
     printf("*******判断链表是否为空*******\n");
     int i = LinkListEmpty(pnod);
     printf("返回值为:%d\n",i);
 }
 void test_LinkListSize()
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******链表长度*******\n");
     LinkListPushBack(&pnod,'a');
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPrint(pnod);
     size_t i = LinkListSize(pnod);
     printf("链表长度为:%d\n",i);
 }
 void test_LinkListReverse()
 {
     LinkNode* pnod;
     LinkListInit(&pnod);
     printf("*******链表逆序排列*******\n");
     LinkListPushBack(&pnod,'a');
     LinkListPushBack(&pnod,'b');
     LinkListPushBack(&pnod,'c');
     LinkListPrint(pnod);
     printf("\n");
 }
 //main.c
 int main()
{
     test_LinkListPushBack();
     test_LinkListPopBack();
     test_LinkListPushFront();
     test_LinkListPopFront();
     test_LinkListFind();
     test_LinkListInsert_before();
     test_LinkListInsert_before2();
     test_LinkListInsert_after();
     test_LinkListErase();
     test_LinkListRemove();
     test_LinkListRemoveAll();
     test_LinkListEmpty();
     test_LinkListSize();
     test_LinkListReverse();
 }

        运行结果

    

    

        

猜你喜欢

转载自blog.csdn.net/yummy_alice/article/details/79705544
今日推荐