15.单向链表的一些基本操作实现

Posted 喵小喵~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了15.单向链表的一些基本操作实现相关的知识,希望对你有一定的参考价值。

  • 运行截图:
  •  


  •  链表快速排序原理:

  •  

  • 链表定义
    struct LinkNode
    {
        int data;
        struct LinkNode *pNext;
    };
    typedef struct LinkNode node;

     

  • 尾部添加节点
    void addback(node **phead, int data)
    {
        //先创建新的结点
        node *pnew = (node *)malloc(sizeof(node));
        pnew->data = data;
        pnew->pNext = NULL;
    
        //如果头结点为空
        if (*phead == NULL)
        {
            //头结点指向pnew
            *phead = pnew;
        }
        else
        {
            //否则备份首地址,找到最后一个
            node *ptemp = *phead;
            while (ptemp->pNext != NULL)
            {
                ptemp = ptemp->pNext;
            }
            ptemp->pNext = pnew;
        }
    
        
    }

     

  • 显示链表
     1 void showall(node *phead)
     2 {
     3     if (phead == NULL)
     4     {
     5         return;
     6     }
     7     else
     8     {
     9         printf("%5d    本节点地址:%p    下一个节点地址:%p\\n", phead->data, phead, phead->pNext);
    10         showall(phead->pNext);//跳到下一个节点
    11     }
    12 }

     

  • 反转显示
    void revshowall(node *phead)
    {
        if (phead == NULL)
        {
            return;
        }
        else
        {
            showall(phead->pNext);//跳到下一个节点
            printf("%d   ,%p,%p\\n", phead->data, phead, phead->pNext);
        }
    }

     

  • 头部插入
     1 void addhead(node **pphead, int data)
     2 {
     3     node *pnew = (node *)malloc(sizeof(node));
     4     pnew->data = data;
     5     pnew->pNext = NULL;//赋值
     6 
     7     if (*pphead==NULL)
     8     {
     9         *pphead = pnew;
    10     }
    11     else
    12     {
    13         pnew->pNext = *pphead;
    14         *pphead = pnew;
    15     }
    16 }

     

  • 寻找第一个指定元素的位置
     1 node *searchfirst(node *phead, int finddata)
     2 {
     3     for (node *p = phead; p != NULL; p = p->pNext)
     4     {
     5         if (p->data == finddata)
     6         {
     7             return p;//返回找到的地址
     8         }
     9     }
    10     return NULL;
    11 }

     

  • 改变第一个指定元素的值
     1 void changefirst(node *phead, int finddata,int newdata)
     2 {
     3     for (node *p = phead; p != NULL; p = p->pNext)
     4     {
     5         if (p->data == finddata)
     6         {
     7             p->data = newdata;
     8         }
     9     }
    10 }

     

  • 删除第一个指定元素
     1 void deleteFirst(node **phead, int finddata)
     2 {
     3     node *p1 = NULL, *p2 = NULL;//p1向前,p2保存p1的上一个位置
     4     p1 = *phead;//保存头结点
     5     while (p1 != NULL)
     6     {
     7         if (p1->data != finddata)
     8         {
     9             p2 = p1;
    10             p1 = p1->pNext;
    11         }
    12         else
    13         {
    14             break;
    15         }
    16     }
    17 
    18     if (p1 == NULL)
    19     {
    20         return;
    21     }
    22     //如果是头结点
    23     if (p1 == *phead)
    24     {
    25         *phead = (*phead)->pNext;
    26         free(p1);//头部删除
    27     }
    28     else
    29     {
    30         p2->pNext = p1->pNext;
    31         free(p1);
    32     }
    33 
    34 }

     

  • 插入元素(在找到的元素之前插入)
     1 void insertFirstHead(node **phead, int finddata,int newdata)
     2 {
     3     node *p1 = NULL, *p2 = NULL;//p1向前,p2保存p1的上一个位置
     4     p1 = *phead;//保存头结点
     5     while (p1 != NULL)
     6     {
     7         if (p1->data != finddata)
     8         {
     9             p2 = p1;
    10             p1 = p1->pNext;
    11         }
    12         else
    13         {
    14             break;
    15         }
    16     }
    17 
    18     if (p1 == NULL)
    19     {
    20         return;
    21     }
    22     
    23 
    24     node *pnew = (node *)malloc(sizeof(node));//新的结点
    25     pnew->data = newdata;
    26     pnew->pNext = NULL;//赋值
    27 
    28      //如果是头结点
    29     if (p1 == *phead)
    30     {
    31          pnew->pNext = p1;
    32          *phead = pnew;
    33     }
    34     else
    35     {
    36         p2->pNext = pnew;
    37         pnew->pNext = p1;
    38     }
    39 }

     

  • 插入元素(在找到的元素之后插入)
     1 void insertFirstBack(node **phead, int finddata, int newdata)
     2 {
     3     node *p1 = NULL, *p2 = NULL;//p1向前,p2保存p1的上一个位置
     4     p1 = *phead;//保存头结点
     5     while (p1 != NULL)
     6     {
     7         if (p1->data != finddata)
     8         {
     9             p2 = p1;
    10             p1 = p1->pNext;
    11         }
    12         else
    13         {
    14             break;
    15         }
    16     }
    17 
    18     if (p1 == NULL)
    19     {
    20         return;
    21     }
    22 
    23     //创建新的结点
    24     node *pnew = (node *)malloc(sizeof(node));
    25     pnew->data = newdata;
    26     pnew->pNext = NULL;//赋值
    27 
    28     //如果是头结点
    29     if (p1 == *phead)
    30     {
    31         p1->pNext = pnew;
    32     }
    33     else
    34     {
    35         pnew->pNext = p1->pNext;
    36         p1->pNext = pnew;
    37     }
    38 }

     

  • 链表冒泡排序
     1 void  bubblesort(node *phead)
     2 {
     3     for (node *p1 = phead; p1->pNext != NULL; p1 = p1->pNext)
     4     {
     5         for (node *p2 = phead; p2 ->pNext != NULL; p2 = p2->pNext)
     6         {
     7             
     8             if (p2->data > p2->pNext->data)
     9             {
    10                 int tmp = p2->data;
    11                 p2->data = p2->pNext->data;
    12                 p2->pNext->data = tmp;
    13             }
    14         }
    15     }
    16 }

     

  • 链表分段,返回中间点,用于递归快速排序链表
     1 node *fen(node *pbegin, node *pback)
     2 {
     3     int key = pbegin->data;//以第一个数据为分段
     4     //核心思想:保证p,q直接的数据都大于等于key,q在p的后面
     5     node *p = pbegin;//标识第一个节点
     6     node *q = pbegin->pNext;//游标标识第二个节点
     7 
     8     while (q != pback)
     9     {
    10         //找到小于key的数据,然后交换
    11         if (q->data < key)
    12         {
    13             //循环下一个节点,并进行赋值(p,q之间的值都大于key)
    14             p = p->pNext;
    15 
    16             int temp = p->data;
    17             p->data = q->data;
    18             q->data = temp;//交换
    19         }
    20         q = q->pNext;//循环游标
    21     }
    22     int temp = p->data;
    23     p->data = pbegin->data;
    24     pbegin->data = temp;//交换
    25 
    26     return p;
    27 }

     

  • 快速排序
    1 void quicksort(node *pbegin,node *pback)
    2 {
    3     if (pbegin != pback)
    4     {
    5         node *pfen = fen(pbegin, pback);//取中间点
    6         quicksort(pbegin, pfen);
    7         quicksort(pfen->pNext, pback);
    8     }
    9 }

     

  • 获取链表的长度
     1 int getnum(node *phead)
     2 {
     3     int i = 0;
     4     while (phead != NULL)
     5     {
     6         i++;
     7         phead = phead->pNext;
     8     }
     9     return i;
    10 }

     

  • 链表反转
     1 void rewind(node **phead)
     2 {
     3     
     4     //备份头节点的地址    位置关系:front back tail
     5     node *front = *phead;
     6     //back在from的后面
     7     node *back = (*phead)->pNext;
     8     //反转后头结点的pNext为NULL
     9     (*phead)->pNext = NULL;
    10     //当后一个不为尾节点
    11     while ( back != NULL)
    12     {
    13         //back节点的后一个节点,用于给back节点赋值
    14         node *tail = back->pNext;
    15         //back节点的pNext为front
    16         back->pNext = front;
    17         //front移到back节点位置
    18         front = back;
    19         back = tail;//back移到tail节点位置
    20     }
    21     *phead = front;
    22 }

     

  • 递归反转
     1 node *digui_rew(node *phead)
     2 {
     3     //在结尾处返回
     4     if (phead == NULL || (phead)->pNext == NULL)
     5     {
     6         return phead;
     7     }
     8     else
     9     {
    10         node *next = phead->pNext;
    11         node *head = digui_rew(next);
    12         next->pNext = phead;
    13         phead->pNext = NULL;
    14 
    15         //第一步递归返回
    16         return head;
    17     }
    18 }

     

  • 判断链表是否有环(追击相遇,一个一次前进一个,一个一次前进两个,如果有环则一定能相遇)
     1 int isCir(node *phead)
     2 {
     3     node *p1 = phead;//一次前进一个
     4     node *p2 = phead;//一次前进两个
     5 
     6     int flag = 0;//0表示没有环
     7     while (p1 != NULL && p2 != NULL && p2->pNext != NULL)
     8     {
     9         p1 = p1->pNext;
    10         p2 = p2->pNext->pNext;
    11         if (p1 == p2)
    12         {
    13             flag = 1;
    14             break;
    15         }
    16     }
    17 
    18     return flag;
    19 }

     

  • 有序链表合并,把link2合并到link1
     1 void merge(node **head1, node **head2)
     2 {
     3     //备份head2的头结点地址,一直循环结束
     4     node *p2 = *head2;
     5     while (p2 != NULL)
     6     {
     7         //如果比头节点的值要小,则把p2变成p1的头结点
     8         if (p2->data < (*head1)->data)
     9         {
    10             node *p2tmp = p2->pNext;//备份p2后一个元素
    11             //把头结点地址*head1传给p2->pNext
    12             p2->pNext = *head1;
    13             //p2的地址传给*head1
    14             *head1 = p2;
    15             //向后遍历
    16             p2 = p2tmp;
    17         }
    18         else
    19         {
    20             //p1是第一个后面的节点的data大于p2->data的节点,核心思想是把P2插入到p1之后
    21             node *p1;
    22             node *p2tmp = p2->pNext;//备份p2后一个元素
    23             for (p1 = *head1; p1->pNext != NULL; p1 = p1->pNext)
    24             {
    25                 if (p1->pNext->data > p2->data)
    26                 {
    27                     break;
    28                 }
    29             }
    30             p2->pNext = p1->pNext;
    31             p1->pNext = p2;
    32             
    33             p2 = p2tmp;
    34         }
    35     }
    36 }

     

  • 链表取中间值
     1 node *findmid(node *phead)
     2 {
     3     if (isCir(phead))
     4     {
     5         return NULL;
     6     }
     7 
     8     node *p1 = phead;
     9     node *p2 = phead;
    10     while (p1 != NULL && p2 != NULL && p2->pNext != NULL)
    11     {
    12         p1 = p1->pNext;
    13         p2 = p2->pNext->pNext;
    14     }
    15     return p1;
    16 }

     

 

完整代码:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 struct LinkNode
  5 {
  6     int data;
  7     struct LinkNode *pNext;
  8 };
  9 typedef struct LinkNode node;
 10 
 11 //尾部添加节点
 12 void addback(node **phead, int data);
 13 //头部插入
 14 void addhead(node **pphead, int data);
 15 //显示链表
 16 void showall(node *phead);
 17 //反转显示
 18 void revshowall(node *phead);
 19 //寻找第一个元素的位置
 20 node *searchfirst(node *phead, int finddata);
 21 //改变第一个元素的值
 22 void changefirst(node *phead, int finddata, int newdata);
 23 //删除第一个元素
 24 void deleteFirst(node **phead, int finddata);
 25 //插入元素(在找到的元素之前插入)
 26 void insertFirstHead(node **phead, int finddata, int newdata);
 27 //插入元素(在找到的元素之后插入)
 28 void insertFirstBack(node **phead, int finddata, int newdata);
 29 //链表冒泡排序
 30 void  bubblesort(node *phead);
 31 //快速排序
 32 void quicksort(node *pbegin, node *pback);
 33 //链表分段,返回中间点
 34 node *fen(node *pbegin, node *pback);
 35 //获取链表的长度
 36 int getnum(node *phead);
 37 //链表反转
 38 void rewind(node **phead);
 39 //递归反转
 40 void digui_rew(node **phead);
 41 //有序链表合并,把link2合并到link1
 42 void merge(node **link1, node **link2);
 43 //链表取中间值
 44 node *findmid(node *phead);
 45 
 46 //尾部添加节点
 47 void addback(node **phead, int data)
 48 {
 49     //先创建新的结点
 50     node *pnew = (node *)malloc(sizeof(node));
 51     pnew->data = data;
 52     pnew->pNext = NULL;
 53 
 54     //如果头结点为空
 55     if (*phead == NULL)
 56     {
 57         //头结点指向pnew
 58         *phead = pnew;
 59     }
 60     else
 61     {
 62         //否则备份首地址,找到最后一个
 63         node *ptemp = *phead;
 64         while (ptemp->pNext != NULL)
 65         {
 66             ptemp = ptemp->pNext;
 67         }
 68         ptemp->pNext = pnew;
 69     }
 70 
 71     
 72 }
 73 
 74 //显示链表
 75 void showall(node *phead)
 76 {
 77     if (phead == NULL)
 78     {
 79         return;
 80     }
 81     else
 82     {
 83         printf("%5d    本节点地址:%p    下一个节点地址:%p\\n", phead->data, phead, phead->pNext);
 84         showall(phead->pNext);//跳到下一个节点
 85     }
 86 }
 87 
 88 //反转显示
 89 void revshowall(node *phead)
 90 {
 91     if (phead == NULL)
 92     {
 93         return;
 94     }
 95     else
 96     {
 97         showall(phead->pNext);//跳到下一个节点
 98         printf("%d   ,%p,%p\\n", phead->data, phead, phead->pNext);
 99     }
100 }
101 
102 //头部插入
103以上是关于15.单向链表的一些基本操作实现的主要内容,如果未能解决你的问题,请参考以下文章

链表1:单向链表的基本操作

链表的java实现(单向双向链表,单向链表的反转)

链表的java实现(单向双向链表,单向链表的反转)

单向链表的Java实现

C语言反转单向链表的代码

简单的单向链表的java实现