单链表基本操作学习

     最近几天学习了一下数据结构中的链表,其实大二的时候老师就教过数据结构这门课的,但我不敢说自己学过数据结构,呵呵!为什么呢?那时候老师讲链表的时候讲的那叫一个深奥啊!又不举个例子演示一番,刚开始兴趣还是有的,可后面听着听着就整个人都不好了。蓝瘦,香菇!......,后来就再也没有听过了,只有期末考试时刷刷往年的题目,应付了过去。所以当时数据结构学的怎么样可想而知!

    其实学习链表主要是得掌握指针的操作以及结构体的用法,当然这里边我觉得链表的操作在数据结构我觉得算是比较难的了。不过通过自己几天的挣扎,算是把单链表的基本操作搞清楚了,想想还是蛮开心的。下面把自己写的代码记录下来,便于日后复习。

/*********************************************************************************
 *      Copyright:  (C) 2017 zoulei
 *                  All rights reserved.
 *
 *       Filename:  list.c
 *    Description:  This file
 *
 *        Version:  1.0.0(2017年07月22日)
 *         Author:  zoulei <zoulei121@gmail.com>
 *      ChangeLog:  1, Release initial version on "2017年07月22日 15时41分56秒"
 *
 ********************************************************************************/

#include <stdio.h>
#include <stdlib.h>
struct student
      {
          int number ; /*学生学号 */
          int score;   /*学生分数 */
          struct student *next;
      };
    int n;
      /* 创建不带头结点的链表, */
    struct student *Createlist()
      {
         struct student *head; /*这里的head是指带数据的第一个节点。*/
         struct student *new;  /*new保存创建的新节点的地址 */
         struct student *tail; /*tail保存原链表最后一个节点的地址 */

         n=1;                  /*创建前链表的节点总数为0:空链表 */
         new=(struct student*)malloc(sizeof(struct student)); /* 分配的内存给第一个节点 */
         if(new==NULL)
          {
             printf("distrubute memory failed!\n");
             return NULL;
          }
         else
          {
             printf("向第%d个节点输入数据:",n );
             scanf("%d,%d",&(new->number),&(new->score));  /* 给第一个节点输入数据 */
          }
         while(new->number!=0)
         {
            if(1==n)       /*创建第一个节点链表*/
            {
              head=new;
              tail=head;
              tail->next=NULL;

            }
            else          /* 创建第二个节点,第三个节点...的链表 */
            {
              new->next=NULL;
              tail->next=new;
              tail=new;
            }

           n++;
           new=(struct student*)malloc(sizeof(struct student));/* 分配的内存给第二个,第三个节点... */
           printf("向第%d个节点输入数据:",n);
           scanf("%d,%d",&(new->number),&(new->score));  /* 给第二个,第三个节点...输入数据 */

         }
         return head;
      }
  /*输出链表中的所有数据*/
void print(struct student*head)
{
   struct student *temp;
   int i=0;
   temp=head;
   while(NULL!=temp)
   {
     i++;
     printf("第%d个节点的数据是:%d,%d\n",i,temp->number,temp->score);
     temp=temp->next;
   }
}
   /* 链表逆序 */
struct student *inverse_list(struct student* phead)
{
     struct student *current=phead; /*指向当前节点需要反转的指针 */
     struct student *pnext;         /*指向下一个需要反转的节点的指针 */
     struct student *plast=NULL;    /* 临时指针,它的作用是保存指向当前结点的指针 */
     printf("逆序后的链表数据输出为:\n");
     while(current->next !=NULL)
     {
        pnext=current->next;       /*当前节点指向下一个节点的指针赋值给pnext */
        current->next=plast;
        plast=current;
        current=pnext;
     }
     /* 这里的循环可以这么理解:假设是第一轮逆序,current->next指向的是第二个节点的地址,将其赋值
      * 给pnext,这时再将临时指针plast赋值给指向第二个节点地址的指针(第一轮plast为初始化NULL),前面
      * 这两段代码的操作作用是将第一个节点与第二个节点断开,第一个节点的next为NULL,这样就将第一个节
      * 点逆序为最后一个节点,下面两段代码是将指向第一个节点地址的指针给plast,将指向第二个节点地址的
      * 指针给current,这样就来到了第二轮逆序,第二轮逆序链表中的第二个节点就好比之前第一个节点,第三个
      * 节点就好比之前的第二个节点,如此循环,直到最后一个节点。
      * */
     current->next=plast; /*这里的plast指向最后一个节点的前一个节点*/
     return current;
}
 /*销毁链表*/
void DestroyList(struct student *head)
{
   struct student *ptr;
   ptr=head;
   printf("销毁链表后各个节点的数据输出:\n");
   while(NULL !=ptr)
   {
      free(ptr);
      printf("%d,%d\n",ptr->number,ptr->score);
      ptr=ptr->next;
   }
}
  /*求链表长度 */
int ListLength(struct student *head)
{
   int i=0;
   while(NULL !=head->next)
   {
      i++;
      head=head->next;
   }
   printf("the length of the linked list is:%d\n",i+1);
   return(i+1);
}
 /* 在单链表的指定位置插入新的节点 */
int Insert_Node(struct student *head)
{
    int i=0;
    int j=1;
    struct student *p1=head;
    struct student *new;
    printf("please input the position which inserted:");
    scanf("%d",&i);
    while((j<i) && (p1 !=NULL)) /*当前节点不为NULL,且输入插入节点的位置存在,然后遍历到该位置执行下面else里面的语句 */
    {
       j++;
       p1=p1->next;
    }
    if(p1 == NULL)
    {
      return 0;
    }
    else
    {
      new=(struct student *)malloc(sizeof(struct student));
      printf("the data which  inserted are:");
      scanf("%d,%d",&new->number,&new->score);

      new->next=p1->next; /*new->next指向要插入那个位置的下一节点,这样就将要插入的节点的前一节点后一节点断开了。*/
      p1->next= new;      /*要插入的的节点的前一节点的p1->next指向要插入的节点的地址new.*/
      return 0;
    }
    printf("向链表插入一个节点后的数据输出为:");
}
  /* 删除指定的某一个节点 */
int DeleteNode(struct student *head)
{
    int i;
    int j=1;
    struct student *p1;
    struct student *p2;
    p2=head;
    printf("please input the node that you will delete :");
    scanf("%d",&i);
    printf("删除原链表中的一个节点后,新链表各个节点的数据输出为:\n");
    while((j<i-1) && (p2 != NULL)) /* 找到要删除的节点*/
    {
       j++;
       p2=p2->next;
    }
    if(p2==NULL)
    {
      return 0;
    }
    else
    {
      p1=p2->next;           /* p1指向了要删除的节点 */
      p2->next=p1->next;     /* 删除节点 */
      free(p1);              /*释放删除节点的内存*/
      return 0;
    }
}
int main(int argc,char**argv)
{
    struct student *head;
    struct student *phead;

    head= Createlist() ;
    ListLength(head);
    DeleteNode(head);
    print(head);

    Insert_Node(head);
    print(head);

    phead=inverse_list(head);
    print(phead);
    DestroyList(phead);
    return 0;
}

运行结果:


更新:

 下面是循环链表的创建,输出数据,插入节点,删除节点基本操作。其实循环链表就是将最后一个节点指向的指针指向了头结点,而不是NULL,所以

循环链表的操作和普通的单链表操作差不多,不同的是循环语句判断改变了。看实例:

1.链表创建函数

 struct student *Createlist()
      {
         struct student *head; /*这里的head是指带数据的第一个节点。*/
         struct student *new;  /*new保存创建的新节点的地址 */
         struct student *tail; /*tail保存原链表最后一个节点的地址 */

         n=1;                  /*创建前链表的节点总数为0:空链表 */
         new=(struct student*)malloc(sizeof(struct student)); /* 分配的内存给第一个节点 */
         if(new==NULL)
          {
             printf("distrubute memory failed!\n");
             return NULL;
          }
         else
          {
             printf("向第%d个节点输入数据:",n );
             scanf("%d,%d",&(new->number),&(new->score));  /* 给第一个节点输入数据 */
          }
         while(new->number!=0)
         {
            if(1==n)       /*创建第一个节点链表*/
            {
              head=new;
              tail=head;
              tail->next=head;

            }
            else          /* 创建第二个节点,第三个节点...的链表 */
            {
              new->next=head;
              tail->next=new;
              tail=new;
            }

           n++;
           new=(struct student*)malloc(sizeof(struct student));/* 分配的内存给第二个,第三个节点... */
           printf("向第%d个节点输入数据:",n);
           scanf("%d,%d",&(new->number),&(new->score));  /* 给第二个,第三个节点...输入数据 */

         }
         return head;
      }

与之前不同的是tail->next指向了head,而不是NULL,新的节点的指针new->next指向了head,不是NULL。

2.链表插入一个节点

int Insert_Node(struct student *head)
{
    int i=0;
    int j=1;
    struct student *p1=head;
    struct student *new;
    printf("please input the position which inserted:");
    scanf("%d",&i);
    while((j<i) && (p1->next !=head))
    {
       j++;
       p1=p1->next;
    }
      new=(struct student *)malloc(sizeof(struct student));
      printf("the data which  inserted are:");
      scanf("%d,%d",&new->number,&new->score);

      new->next=p1->next;
      p1->next= new;
      return 0;

    printf("向链表插入一个节点后的数据输出为:");
}
与单链表操作不同之处在于while()循环语句有p1!=NULL变为p1->next!=head,且没有了if...else的判断语句。

3.链表删除一个节点

int DeleteNode(struct student *head)
{
    int i;
    int j=1;
    struct student *p1;
    struct student *p2;
    p2=head;
    printf("please input the node that you will delete :");
    scanf("%d",&i);
    printf("删除原链表中的一个节点后,新链表各个节点的数据输出为:\n");
    while((j<i-1) && (p2->next != head)) /* 找到要删除的节点*/
    {
       j++;
       p2=p2->next;
    }
    if(p2->next==head)
    {
      return 0;
    }
    else
    {
      p1=p2->next;           /* p1指向了要删除的节点 */
      p2->next=p1->next;     /* 删除节点 */
      free(p1);
      return 0;
    }
}
循环语句while()里面由之前的p!=NULL变为p2->next!=head,if()语句里面由p2==NULL变为p2->next==head。

不过这里头结点是不能删除的。只能删除头结点后面的节点。准确来说循环链表中是没有头节点的说法,但是这里为了叙述方便,

才用头结点来表达。

4.输出各个节点中的数据

void print(struct student*head)
{
   struct student *temp;
   int i=1;
   temp=head->next;
   printf("第%d个节点的数据是:%d,%d\n",i,head->number,head->score);
   while(temp !=head)
   {
     i++;
     printf("第%d个节点的数据是:%d,%d\n",i,temp->number,temp->score);
     temp=temp->next;
   }
}
循环语句中指针由指向NULL变为了指向head。

5.销毁链表

void DestroyList(struct student *head)
{
   struct student *ptr;
   ptr=head->next;
   printf("销毁链表后各个节点的数据输出:\n");
   while(head !=ptr)
   {
      free(ptr);
      printf("%d,%d\n",ptr->number,ptr->score);
      ptr=ptr->next;
   }
   free(head);
}









  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值