数据结构-线性表-单链表(学习笔记)

   一、链表的概念

    1. 链式存储结构:

              结点在存储器中的位置是任意的,即逻辑上的相邻的数据元素在物理上不一定相邻

    2. 线性表的链式表示又称为非顺序映像或链式映像

    3. 存储单元可以是连续的、不连续的、也可以是零散的,访问时只能通过指针依次扫描

    4.一个结点由数据域和指针域构成,头指针记录第一个元素的地址,前一个结点的指针域保存下一个结点的地址,单链表的结点只有一个指针域

    5. 单链表是由头指针唯一确定的,因此单链表可以用头指针的名字来命名

    6. 头指针:指向链表中第一个结点的指针

        首元节点 :链表中存储第一个数据元素a1的结点

        头结点:在首元结点之前附设的一个结点

   7.  两种形式

   1)不带头结点

          头指针直接存放第一个有数据元素的结点的地址

   2)带头结点

         头指针存放头结点的地址

  8.  如何表示空表?

    1)无头:头指针为空时,header==NULL

    2)有头:头指针的指针域为空,header->next==NULL(next是头结点的指针域)

  9. 带头结点好处

   1)处理首元结点时与其他结点一致,无需特殊处理

   2)便于统一处理空表和非空表

 10. 头结点包含什么?

      指针域存放首元结点的地址,而数据域中可以为空,也可存放线性表的长度,因为它不是数据元素,所以统计表长时不能将它统计进去 

     二、单链表的定义

 1.   结点分为数据域和指针域,数据域可以是任意类型的数据,int,float,char等等,而指针域是指向下一个结点,结点是结构体类型,因此指针域应是结构体类型

解释:图中定义了一个结构体类型的结点,包括任意类型的数据域和结构体类型的指针域,加上typedef是为结构体起了别名,后续操作中不用再写struct Lnode了,而*LinkList是定义了一个指向结构体Lnode的指针类型,所以在定义头指针时,可以写成Lnode*header,也可以写成LinkList header

如果想要定义一个单链表,就可以定义为Lnode*header,或者是LinkList header了,因为头结点的名字代表整个链表,定义结点指针也可以使用这两种方式

三、单链表的相关算法

即构造一个空的单链表,即有一个头结点,头结点的指针域为空

1.单链表的初始化

算法步骤:

1)生成新结点作为头结点,用头指针header指向头结点

2)将头结点的指针域置空

代码实现:

//初始化一个单链表
#include<iostream>
using namespace std;


//生成新结点作为头结点,用头指针header指向头结点
1)定义结点
typedef struct Lnode
{
    int data;//假设数据是int类型
    struct Lnode*next;//指针域

}Lnode,*LinkList;//Lnode为别名,*LinkList为指向结构体的指针类型



2)设置一个状态函数,进行初始化
int InitList_L(LinkList &header)//LinkList &header是函数引用,可以修改main中的实参,header既是原名,也是别名
{
    //为结点开辟空间
   header=new Lnode();//new出来后返回的是内存空间的首地址,所以要用指针接收
    //将头结点的指针域置空
   header->next=NULL;
   return 1;

}



3)看看是否初始化成功
int main()
{

   LinkList header;//定义头结点,也可用Lnode*header定义
   //定义变量,调用状态函数
   int a=InitList_L(header);
   cout<<a<<endl;//如果打印了1,说明初始化成功


system("pause");
return 0;

}



2. 几个简单算法

1)判断链表是否为空

   空表是链表中无元素,但头指针和头结点仍然存在

   算法思路:判断头结点指针与是否为空

   代码实现:

//初始化一个单链表
#include<iostream>
using namespace std;


//生成新结点作为头结点,用头指针header指向头结点
1)定义结点
typedef struct Lnode
{
    int data;//假设数据是int类型
    struct Lnode*next;//指针域

}Lnode,*LinkList;//Lnode为别名,*LinkList为指向结构体的指针类型



2)设置一个状态函数,进行初始化
int InitList_L(LinkList &header)//LinkList &header是函数引用,可以修改main中的实参,header既是原名,也是别名
{
    //为结点开辟空间
   header=new Lnode();//new出来后返回的是内存空间的首地址,所以要用指针接收
    //将头结点的指针域置空
   header->next=NULL;
   return 1;

}



//判断链表是否为空
int ListEmpty(LinkList &header)
{
   if(header->next==NULL)
    {
        return 1;
    }

   else
        return 0;//非空返回0
}





3)看看是否初始化成功
int main()
{

   LinkList header;//定义头结点,也可用Lnode*header定义
   //定义变量,调用状态函数
   int a=InitList_L(header);
   cout<<a<<endl;//如果打印了1,说明初始化成功
   cout<<"-----------------------------------------------------"<<endl;

   //看看链表是否为空
    int b=ListEmpty(header);
    cout<<a<<endl;//如果打印了1,说明不为空,打印0,则为空


system("pause");
return 0;

}


2)单链表的销毁

   销毁后链表不存在,包括头结点和头指针

   算法思路:从头指针开始,依次释放所有结点

   代码实现 :

//初始化一个单链表
#include<iostream>
using namespace std;


//生成新结点作为头结点,用头指针header指向头结点
1)定义结点
typedef struct Lnode
{
    int data;//假设数据是int类型
    struct Lnode*next;//指针域

}Lnode,*LinkList;//Lnode为别名,*LinkList为指向结构体的指针类型



2)设置一个状态函数,进行初始化
int InitList_L(LinkList &header)//LinkList &header是函数引用,可以修改main中的实参,header既是原名,也是别名
{
    //为结点开辟空间
   header=new Lnode();//new出来后返回的是内存空间的首地址,所以要用指针接收
    //将头结点的指针域置空
   header->next=NULL;
   return 1;

}




//销毁链表,没有设置两个指针,而是让头指针也跟着定义的新指针移动
int DestoryList_L(LinkList& header)
{
    //设置一个可移动的指针,让它依次指向每一个结点
    Lnode* pCurrent= header;//一开始都指向头结点
    //销毁链表要从头结点开始,所以让pCurrent先指向头结点,即让把头指针赋值给pCurrent
    //利用循环
    while (pCurrent != NULL)
    {
        header = pCurrent;//循环第一次时,都指向头结点,二者谁赋给谁是一样的,这条也可不加
        //让pCurrent向后移动
        pCurrent = pCurrent->next;
        //释放
        delete pCurrent;
    }

    delete header;//将头结点和头指针释放
    return 0;

}







3)看看是否初始化成功
int main()
{

   LinkList header;//定义头结点,也可用Lnode*header定义
   //定义变量,调用状态函数
   int a=InitList_L(header);
   cout<<a<<endl;//如果打印了1,说明初始化成功

cout<<"-----------------------------------------------------------"<<endl;
   int b=DestoryList_L(header);
   cout<<b<<endl;//如果返回0,说明销毁成功



system("pause");
return 0;

}


  3)单链表的清空

    链表仍存在,但链表中无元素,成为空链表,但头指针和头结点仍然存在

    算法思路:依次释放所有结点,并将头结点指针域设置为空

   先给链表中结点附上值,更方便观察是否清空

//初始化一个单链表
#include<iostream>
using namespace std;


//生成新结点作为头结点,用头指针header指向头结点
1)定义结点
typedef struct Lnode
{
    int data;//假设数据是int类型
    struct Lnode*next;//指针域

}Lnode,*LinkList;//Lnode为别名,*LinkList为指向结构体的指针类型


2)设置一个状态函数,进行初始化
int InitList_L(LinkList &header)//LinkList &header是函数引用,可以修改main中的实参,header既是原名,也是别名
{
    //为结点开辟空间
   header=new Lnode();//new出来后返回的是内存空间的首地址,所以要用指针接收
    //将头结点的指针域置空
   header->next=NULL;
   return 1;

}


//创建一个链表
void test()
{
   //创建6个独立的结点
    Lnode node1={10,NULL};
    Lnode node2={20,NULL};
    Lnode node3={30,NULL};
    Lnode node4={40,NULL};
    Lnode node5={50,NULL};
    Lnode node6={60,NULL};
  
   //连接起来
    node1.next=&node2;
    node2.next=&node3;
    node3.next=&node4;
    node4.next=&node5;
    node5.next=&node6;
   //node6指针域为空

  //设置辅助指针进行遍历
  Lnode*p=&node1;
  while(p!=NULL)
     {
        cout<<p->data<<endl;
         p=p->next;
     }
}

//清空链表
void ClearList(LinkList &header)
{
   //因为在清空中,头指针和头结点要保留,所以就让头指针始终指着头结点,另外设置两个指针移动
    Lnode*pCurrent=header->next;//pCurrent指着首元结点
    Lnode*pNext=pCurrent->next;//pNext指着首元结点后面的那个结点
  while(pCurrent!=NULL)
       {
         //清空一个结点前先得获得里面保存的下一个结点的地址
         pNext=pCurrent->next;
         delete pCurrent;
         //让pCurrent指向下一个结点
         pCurrent=pNext;
          
       }
   
  //将头结点指针域置空
   header->next =NULL;

}

3)看看是否赋值成功
int main()
{

  
  test();
  

system("pause");
return 0;

}

4) 求单链表的表长

注意:头结点不算入其中

算法思路:从首元结点开始,设置一个计数器,依次计数所有结点

      代码实现:

        

//初始化一个单链表
#include<iostream>
using namespace std;


//生成新结点作为头结点,用头指针header指向头结点
1)定义结点
typedef struct Lnode
{
    int data;//假设数据是int类型
    struct Lnode*next;//指针域

}Lnode,*LinkList;//Lnode为别名,*LinkList为指向结构体的指针类型



2)设置一个状态函数,进行初始化
int InitList_L(LinkList &header)//LinkList &header是函数引用,可以修改main中的实参,header既是原名,也是别名
{
    //为结点开辟空间
   header=new Lnode();//new出来后返回的是内存空间的首地址,所以要用指针接收
    //将头结点的指针域置空
   header->next=NULL;
   return 1;

}



//创建一个链表
void test()
{
   //创建6个独立的结点
    Lnode node1={10,NULL};
    Lnode node2={20,NULL};
    Lnode node3={30,NULL};
    Lnode node4={40,NULL};
    Lnode node5={50,NULL};
    Lnode node6={60,NULL};
  
   //连接起来
    node1.next=&node2;
    node2.next=&node3;
    node3.next=&node4;
    node4.next=&node5;
    node5.next=&node6;
   //node6指针域为空

  //设置辅助指针进行遍历
  Lnode*p=&node1;
  while(p!=NULL)
     {
        cout<<p->data<<endl;
         p=p->next;
     }
}

//计算链表表长
int ListLength_L(LinkList&header)
{

   //设置一个指针,让它先指向首元结点
   Lnode*pCurrent=header->next;
   int i=0;//设置计数器
   while(pCurrent!=NULL)//遍历链表
       {
          i++;//结点不为空时
          pCurrent=pCurrent->next;//移动指针
       }
   return i;//返回元素个数,即表长

}



3)看看是否赋值成功
int main()
{
  //定义头指针
  Lnode*header;
  InitList_L(header);
  test();
  int i=ListLength_L(header);
  cout<<"表长为:"<<i<<endl;

system("pause");
return 0;

}

3. 几个较难算法

1)取第i个元素值

算法思路:设置一个可移动的指针,让它指向首元结点,逐渐移动,扫描每一个结点

                  设置一个计数器 j, 让它的初值为1,指针每移动到下一个结点,就加一

                  当j与i 相同时,说明找到了第i个值

还要考虑特殊情况,比如i不能小于j,i也不能大于最大值,即指针不为空

 代码实现:

//初始化一个单链表
#include<iostream>
using namespace std;


//生成新结点作为头结点,用头指针header指向头结点
1)定义结点
typedef struct Lnode
{
    int data;//假设数据是int类型
    struct Lnode*next;//指针域

}Lnode,*LinkList;//Lnode为别名,*LinkList为指向结构体的指针类型


2)设置一个状态函数,进行初始化
int InitList_L(LinkList &header)//LinkList &header是函数引用,可以修改main中的实参,header既是原名,也是别名
{
    //为结点开辟空间
   header=new Lnode();//new出来后返回的是内存空间的首地址,所以要用指针接收
    //将头结点的指针域置空
   header->next=NULL;
   return 1;

}



//创建一个链表
void test()
{
   //创建6个独立的结点
    Lnode node1={10,NULL};
    Lnode node2={20,NULL};
    Lnode node3={30,NULL};
    Lnode node4={40,NULL};
    Lnode node5={50,NULL};
    Lnode node6={60,NULL};
  
   //连接起来
    node1.next=&node2;
    node2.next=&node3;
    node3.next=&node4;
    node4.next=&node5;
    node5.next=&node6;
   //node6指针域为空

  //设置辅助指针进行遍历
  Lnode*p=&node1;
  while(p!=NULL)
     {
        cout<<p->data<<endl;
         p=p->next;
     }
}

//取第i个值
int GetElem(LinkList&header,int i,int &e)//int &e为返回值
{
    //设置指针指向首元结点
    Lnode*pCurrent=header->next;
    int j=1;//计数器
    while(pCurrent!=NULL&&i>j)//j==i时退出循环
        {
            j++;
           pCurrent=pCurrent->next;
        }
    if(pCurrent==NULL||j>i)//
       {
         return;
       }
    e=pCurrent->data;
    return e;

}


3)看看是否赋值成功
int main()
{
  //定义头指针
  Lnode*header;
  InitList_L(header);
  int e=GetElem(header,2,e);
  cout<<"第i个值为:"<<e<<endl;


system("pause");
return 0;

}


2) 按值查找

     根据指定数据获取该数据所在的位置(地址)

算法思路:从首元结点开始,依次与要找的值比较

                  如果找到一个与待找值相同的数据元素,就返回它在链表中的位置(地址)

                  如果查遍整个链表都没有,就返回0或NULL

 

代码实现:

//初始化一个单链表
#include<iostream>
using namespace std;


//生成新结点作为头结点,用头指针header指向头结点
1)定义结点
typedef struct Lnode
{
    int data;//假设数据是int类型
    struct Lnode*next;//指针域

}Lnode,*LinkList;//Lnode为别名,*LinkList为指向结构体的指针类型


2)设置一个状态函数,进行初始化
int InitList_L(LinkList &header)//LinkList &header是函数引用,可以修改main中的实参,header既是原名,也是别名
{
    //为结点开辟空间
   header=new Lnode();//new出来后返回的是内存空间的首地址,所以要用指针接收
    //将头结点的指针域置空
   header->next=NULL;
   return 1;

}


//创建一个链表
void test()
{
   //创建6个独立的结点
    Lnode node1={10,NULL};
    Lnode node2={20,NULL};
    Lnode node3={30,NULL};
    Lnode node4={40,NULL};
    Lnode node5={50,NULL};
    Lnode node6={60,NULL};
  
   //连接起来
    node1.next=&node2;
    node2.next=&node3;
    node3.next=&node4;
    node4.next=&node5;
    node5.next=&node6;
   //node6指针域为空

  //设置辅助指针进行遍历
  Lnode*p=&node1;
  while(p!=NULL)
     {
        cout<<p->data<<endl;
         p=p->next;
     }
}

//按值查找,返回值的地址
Lnode*LocateELem_L(LinkList &header,int e )
{
   //设置指针指向首元结点
   Lnode*pCurrent=header->next;
   //利用循环查找
   while(pCurrent->data!=e&&pCurrent!=NULL)
    {
        pCurrent=pCurrent->next;//移动指针
    }
   
    return pCurrent;

}


3)看看是否赋值成功
int main()
{
  Lnode*header;
  InitList_L(header);
  test();
  //定义变量接收
  Lnode*p=LocateELem_L(header,20);
  cout<<p<<endl;


system("pause");
return 0;

}

算法思路:

        根据指定数据获取该数据位置序号

代码实现:

//初始化一个单链表
#include<iostream>
using namespace std;


//生成新结点作为头结点,用头指针header指向头结点
1)定义结点
typedef struct Lnode
{
    int data;//假设数据是int类型
    struct Lnode*next;//指针域

}Lnode,*LinkList;//Lnode为别名,*LinkList为指向结构体的指针类型


2)设置一个状态函数,进行初始化
int InitList_L(LinkList &header)//LinkList &header是函数引用,可以修改main中的实参,header既是原名,也是别名
{
    //为结点开辟空间
   header=new Lnode();//new出来后返回的是内存空间的首地址,所以要用指针接收
    //将头结点的指针域置空
   header->next=NULL;
   return 1;

}


//创建一个链表
void test()
{
   //创建6个独立的结点
    Lnode node1={10,NULL};
    Lnode node2={20,NULL};
    Lnode node3={30,NULL};
    Lnode node4={40,NULL};
    Lnode node5={50,NULL};
    Lnode node6={60,NULL};
  
   //连接起来
    node1.next=&node2;
    node2.next=&node3;
    node3.next=&node4;
    node4.next=&node5;
    node5.next=&node6;
   //node6指针域为空

  //设置辅助指针进行遍历
  Lnode*p=&node1;
  while(p!=NULL)
     {
        cout<<p->data<<endl;
         p=p->next;
     }
}

//按值查找,返回值的地址
int LocateELem_L(LinkList &header,int e )
{
   //设置指针指向首元结点
   Lnode*pCurrent=header->next;
   int j=1;//设置计数器
   //利用循环查找
   while(pCurrent->data!=e&&pCurrent!=NULL)
    {
        pCurrent=pCurrent->next;//移动指针
        j++;
    }
   if(pCyrrent->data==e)
    {
        rerurn j;
    }

   else
       return 0;

}


3)看看是否赋值成功
int main()
{
  Lnode*header;
  InitList_L(header);
  test();
  //定义变量接收
  int j=LocateELem_L(header,20);
  cout<<j<<endl;


system("pause");
return 0;

}

 3)插入结点

在第i个结点前插入值为e的新结点

算法思路: 首先要找到第i-1个结点,让指针Prev指向它,让指针pCurrent指向要插入的结点

                   插入新结点时,先让新结点的指针域指向原i结点的数据域,再让i-1结点的指针域指向            新节点的数据域(写代码时一定要按这个顺序,先后再前)

代码实现:

//在值为oldval的位置插入一个新的数据newval(因为插入后oldval的位置会变化),函数的参数首先要获得这个链表,这个链表的数据类型也就是第一个结点的数据类型,也就是struct LinkNode*类型,头结点起名为header,获得头结点就获得了整个链表
void InsertByValue_LinkList(struct LinkNode*header,int oldval,int newval)
{
   if(NULL==header)//判断一下链表是否为空链表
     {
       return;
     }
   //利用双指针,一次移动两个指针,插入的结点一定会在这两个指针中间
   //设置两个辅助指针变量
 struct LinkNode *pPrev=header;//让前一个指针默认指向头结点
 struct LinkNode *pCurrent=pPrev->next;//pPrev->next就是next,都是指针
 
 while(pCurrent!=NULL)//不为空的原因和上面一样
  {
     if(pCurrent->data==oldval)//说明pCurrent已经指向了oldval
       {
          break;
       }
    //如果没有找到oldval,则同时移动两个指针
     pPrev=pCurrent;// pPrev移动到了pCurrent刚才的位置
     pCurrent=pCurrent->next;
    
   //这个过程结束后只有两个结果,1是pCurrent找到了oldval,2是pCurrent最后指向了空,因此这是要判断一下
     if(pCurrent==NULL)
      {
        return;//没有就直接返回吧
      }
 
   //创建新结点
   Lnode *newnode=new Lnode();
   newnode->data=newval;//将刚才输入的值赋给新结点
   newnode->next=NULL;//因为现在只创建了一个新结点,新结点相对头结点来说是最后一个,所以后面为空
 
   //新结点插入到链表中
  newnode->next=pCurrent;
  pPrev->next=newnode;
 
  }
 
}

4)  删除第i个结点

算法思路:首先找到i-1中存储的i的位置,保存要删除的值

                  令p指向i-1,再让p->next指向i+1

                   关键一步:p->next=p->next->next,意思是把i+的地址赋给i

代码实现:

     

//将线性表中第i个数据元素删除
int ListDelete_L(LinkList &header,int i,int &e)
{
    
   //设置指针和计数器,指针的目的还是想找第i-1个数据元素
   Lnode*pCurrent=header;//从头结点开始,header是头指针
   int j=0;
   while(pCurrent->next!=NULL&&j<i-1)//当链表不为空并且还没找到i-1个节点时,要继续向后找
   {
       j++;
       pCurrent=pCurrent->next;
   }
   if(pCurrent->next==NULL||j>i-1)
    {
         return -1;
    }
  //设置一个临时指针用来保存被删节点的地址
    Lnode*q=pCurrent->next;//此时pCurrent已经指到了i-1的位置
  //改变i-1结点的指针域
    pCurrent->next=q->next;
   //保存删除节点的数据域
   e=q->data;
   delete q;

return 0;

}

四、建立单链表

1 . 头插法

   算法时间复杂度为O(n)

  1)从一个空表开始,重复读入数据

  2)生成新结点,将读入数据存放到新结点的数据域中

  3)从最后一个结点开始,依次将各结点插入到链表前端

算法思路:

       

void CreateList_H(LinkList &L,int n)//表示要输入n个元素
{
   //创建头结点
   Lnode*header=new Lnode();
   header->next=NULL;//建立一个带有头结点的单链表
   //头插法形象表示如上图
  for(int i=n;i>0;i--)//先插入最后一个数,然后依次向前插
     {
        //创建新结点
       p=new Lnode();//即将插入的新结点
       cin>>p->data;//依次输入数字,存入各结点的数据域中
       p->next=header->next;//将新结点与后面的结点连接起来
       header->next=p;//将新结点与头结点连接起来

     }

}

 2. 尾插法

算法时间复杂度为O(n)

//函数定义
 
//定义函数来初始化链表,初始化后需要返回链表中的结点,即返回对应指针
//当链表为空时,只有一个头结点,头结点后面为空
struct LinkNode* Init_LinkList()
{
    //创建头结点,申请动态空间,使用malloc,返回对应指针,不能在堆上和和栈上创建,不然函数使用完后节点就消失了,只能用malloc函数,而c++上优先使用new和delete
    //因为想到使用malloc函数会返回指针类型,所以声明时的数据类型就写的是struct LinkNode*,而不是struct LinkNode
    //指向头节点的指针就代表着头结点
   struct LinkNode * header=malloc(sizeof(struct LinkNode));
   header->data=-1;//header在此处是指针,指向头结点,而header->data则是获取头结点中的数据,又因为头结点是没有数据的,我们可以任意给他一个值,反正也不会使用它
   header->next=NULL;//初始时只有头结点,后面没有节点,而header->next表示下一个节点的地址,还没有设置,哪里来的地址呢,因此设为空
 
 
  //等待用户输入
 
//设置一个尾部指针
struct LinkNode *pRear=header;//rear是尾的意思,刚开始默认这个尾部指针和头指针是一回事
 int val=-1;//相当于初始化data
 while(1)//利用循环不断创建新节点,不断赋值
{
   printf("请输入插入的数据:\n");
   scanf("%d",&val);
   if(val==-1)//为了让用户输入一个与初始值不同的值
    {
       break;
    }
   //判断结束后,不符合时用户就可以进行第二次输入
   //插入数据时,是在头结点后依次向后插,但再插入的过程中尾部一直发生变化,这样在每次插入时,都需要找到尾部结点,有点麻烦。那能不能在插入的过程中先设置一个指针,让指针始终指向尾部,先让指针指向头结点,因为初始后面没有节点,随着逐渐插入结点,这个指针也跟着向后移动,直到真正的尾部
 
    
  //数据有了,此时要创建新结点来接受这些数据了
  //动态链表中创建节点就是创建指针
  struct LinkNode *newnode=malloc(sizeof(struct LinkNode));
  newnode->data=val;//将刚才输入的值赋给新结点
  newnode->next=NULL;//因为现在只创建了一个新结点,新结点相对头结点来说是最后一个,所以后面为空
 
 
  //将新结点插入到链表中
  //因为pRear初始时指向头结点,如果要连接下一个结点,必须获得下一个节点的位置,然后让pRear再指向第二个结点,依此类推,这个过程和遍历有点像,但不是遍历,而是不断让pRear指向新尾部,直到真正的尾部
   pRear->next=newnode; //newnode是指向新结点的指针,随着结点插入,newnode不断更新,新结点的地址不断更新,pRear->next,初始next是头结点的next,这样可以获得下一个结点的地址,newnode不断赋值给pRear->next,pRear这个指针也就不断去寻找新的尾部
  //因为newnode初始化是空的,因此这里给不给值都没关系
 
  //更新尾部指针指向
   pRear=newnode;//因为newnode指针始终指向新创建的结点,如果想让pRear这个尾部指针移动,就把newnode的值赋给pRear
 
  //小总结:上面这两行代码代表不同含义。第一行是让头结点的next指向newnode,而pRear又是指向头结点的next,也就相当于是next的内容,也就是新结点的地址,就是newnode,目的是获取新节点的地址。而第二行
是为了改变尾部指针的指向,让它不断去寻找新的尾部,直到真正的尾部。
 
 
}
//结束之后,我们要获得这个链表,就返回它的头结点就行了
return header;
  
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值