数据结构学习笔记——链表

1.什么是链表?

我的理解是:链表就是由一系列的节点组成,而每个节点又包括了两个部分;一部分是数据域,用来储存数据,另一部分指针域,用来指向下一节点。最后把这些节点串起来就形成了链表。

1.1节点构造

struct list_node
{
    int     data ; // 定义数据域,用于存储数据  
    struct  list_node *next ; //定义指针域,可以用来访问节点数据,也可以遍历,指向下一个节点

};

1.2链表的构造

首先了解链表的组成部分:
在这里插入图片描述
说明:
头节点:在单链表的第一个结点之前附设一个结点,它没有直接前驱,称之为头结点,头结点的数据域可以不存储任何信息,指针域指向第一个节点(首节点)的地址。头结点的作用是使所有链表(包括空表)的头指针非空。

2.创建链表

2.1 单向链表

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct list_node     //定义结构体
{
int      data ;       //数据域
struct   list_node *next ;   //指针域
}
typedef struct list_node list_single ;

int main(void)
{
      list_single      *node = NULL ; //定义一个头指针

node = (list_single *)malloc(sizeof(list_single)); //分配内存空间

if(node == NULL)
{
     printf("分配空间失败\n");
}

    memset(node,0,sizeof(list_single)); //清空
    node->data = 123 ;        //给链表节点的数据域赋值
    node->next = NULL ;      //将链表的指针域指向空

      printf("node_data=%d\n",node->data);
      printf("node_next=%d\n",node->next);
      free(node);

 return 0 ;

}

运行结果:
在这里插入图片描述
该链表就是:

在这里插入图片描述上述程序中出现了malloc函数,该函数分配的内存大小至少为参数所指定的字节数 ,而且malloc和free是配对的,如果申请后不释放就是内存泄露,如果无故释放那就是什么也没做,释放只能释放一次,如果一块空间释放两次或者两次以上会出现错误(但是释放空指针例外,释放空指针也等于什么也没做,所以释放多少次都是可以的。)
详细解释可以参考:malloc函数详解

2.2遍历输出链表

void looklist()
           struct list_node *newp =head;     //定义一个临时变量指向头节点
           //通过循环遍历整个链表并输出
           while(newp != NULL{
               printf("%d\n",newp->data);
               newp = newp->next;
           }
           
      

2.3查询链表某节点

struct Node* FindNode(int a )
{
    struct list_node *newp=head;
    while( newp != NULL//遍历整个链表
    {
        if(data == temp->data)     //找到则返回该节点
             return temp;
         temp = temp->next;
    }
         return NULL;    //未找到
}

2.4尾增加一个节点

void addlist(int data)
{
      //创建一个新节点,并申请内存空间
      struct list_node* newp=(struct list_node*)malloc(sizeof(struct list_node));
      //第一种是链表为空,即一个节点也没有
      if(head = NULL{
           head = newp;
      }
      else//第二种链表不为空
      {
             end->next=newp;
      }
      end = newp; //尾结点始终指向最后一个
}

2.5尾删除一个节点

void delectend()
{
       //第一种链表为空
       if(end = NULL{ 
              printf("链表为空,无需删除\n");
              return 0}
       //第二种链表不为空
       //只有一个节点
       if (head == end)
       {
              free(head);
              head=NULL;
	      end=NULL; 
       }
       else //多个节点
       {
             struct list-node* newp =head; 
             while (temp->next!=end)//找到尾部
             {
                  newp= newp->next;
             }

             //释放尾巴
             free(end);
             //再将倒数第二个设为end
            end=temp;
           //尾巴指针为NULL
           end->next=NULL;

       }
}

2.6头删除一个节点

void delecthead()
{
    struct list_node* newp=head;   //保留旧头
    //判断是否为空
    ifNULL == head)
    {
          printf("链表为空,无需删除\n");
          return 0}  
    
    head=head->next;//头的第二个节点变成新的头
    free(newp);      //将旧头空间释放
}

2.7删除指定节点

void delectlist(int data)
{
   //判断链表是否为空
   if(NULL==head)
   {
       printf("链表为空,无需删除\n");
       return 0}
   //不为空,则遍历链表找到这个节点
   struct list_node* newp = head
       while(newp !=NULL)
       {
           if(data == newp->data)
           {
                  return newp;
           }
           newp = newp->next;
       }
       if(NULL == newp)
       {
           printf("查无此点\n");
           return 0}
       if(head==end)  //只有一个节点
       {
            free(head);
            head = NULL;
            end=NULL;
       }
       else if(head->next==end) //有两个节点
       { if(end==newp)
           { 	delestend(); }
       else if(newp==head)
           {	delecthead(); }
       }
       else //多个节点时
       {
            //看是删除头还是删除尾
            if(end==newp)
                 delectend();
            else if(temp==newp)
                 delecthead();
            else
            {  //遍历,找到需要删除的前一个
                   struct list_node*pt =head;
                   while(pt->next!=newp)
                   {
                        pt=pt->next;
                   }
                    pt->next=newp->next;
                    free (newp);
            }
       }
     }
       
    

如图所示如图所示

2.8增加指定节点

void addlist(int index,int data)
{
//首先判断是否为空
      if (NULL==head)
      {
            printf("链表为空\n");
            return 0}
      struct list_node* pt =FindNode(index);   //调用之前定义的查询
     
      if(NULL==pt)    //没有此节点
      {
               printf("没有找到指定节点\n");
               return 0}     
      //若有节点,则创建临时节点
      struct list_node* newp =(struct Node *)malloc(sizeof(struct Node));
      newp->data=data;
      newp->next=NULL;

      if (pt == end)   //末端插入
      {
         end->next=newp;
         end=newp;
      }
      else   //中间插入
      {
           newp->next=pt->next;
           pt->next=newp;
      }
}

在这里插入图片描述
在中间也类似。

2.9 主函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct list_node
{
    int     data ; 
    struct  list_node *next ; 
 }

struct  list_node* head= NULL;
struct  list_node* end = NULL;
//定义链表头尾指针

void main ()
{

    struct Node* FindNode;
    for(i=0;i<10;i++addlist(i);    //直接调用之前的2.4中的函数,进行链表的生成

/*     delectend();  //删除尾节点
     delectlist(5);   //删除第五个节点
   */  
     looklist()        //遍历链表,输出
          
}

3.单向和双向循环链表

1.单向循环链表
就是表的最后一个元素指向了头节点而不是为空(null)
在这里插入图片描述

2.双向循环链表
相当于两个单向循环链表的叠加。
在这里插入图片描述

4.总结

通过一段时间leetcode网站的刷题,发现了自己的很多问题,之前学习的基础知识不够扎实,在刷题有很多时候一道题需要很长的时间,而且很多答案不是特别看得懂,思路不清晰,所以打算整理一下一些数据结构方面的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值