链表链表!!!结构体指针模拟链表

链表>

  • 由于无法得知new出新节点的次序,不可以写部分题,例如:link
  • 这道题只能使用数组模拟链表来做,故结构体指针链表最好做为一种了解链表的工具,其限制性很大相较数组模拟链表无优点
  • 我真是被链表搞的头都大了,一开始就没学好多东西,结构体指针都没咋学,导致做链表类题的时候直接就跳(尽管我没做过多少题)
  • 然后我花了好几天时间才勉强看懂大佬们300行代码的简单教程,对我个新手来说就是折磨,搜了大概十几篇博文,三个浏览器换着看换着理解,就在今天,突然大悟(主要是我回去复习了一下指针和结构体),我看懂了,所有在这里我慢慢剖析一下链表
  • 只是为了我自己总解理解所用,估计像我一样的新手也喜欢我这种”细嚼慢咽“的讲述,哈哈哈哈哈。咳咳!!好了不废话了,开始叙述了

首先你得懂结构体和指针(不懂也没事我尽量讲清楚一点)

  • 只需要下面一行代码,就能把代码模拟出来了,注意只是模拟出来了线性结构,赋值和输出还得靠函数来完成
struct node//node是节点,每个节点存储一个数据和指向下个节点的指针
{
    int data;
    struct node* next;
};
  • node就是节点,一个节点包括两部分,数据域和指针域,如下面的图所示,形成线性结构
dataA/nextA
dataB/nextB
dataC/nextC
  • 注指针指向下一个节点的指针p->data,代表本节点元素,p->next若为空则代表到达了尾部,因为这种关系就少不了初始定义:
操作一:初始化
Linklist::Linklist()
{
    head=new node;
    head->data=0;//初始化头节点对应的元素为0
    head->next=NULL;//初始化下一个节点为空
}
  • 什么?你看不懂Linklist::Linklist() 这是为了多个函数的实现而把所有可能的操作封装在了一个大类里,当然你可以使用结构体,毕竟他们没区别,我把大类给写一下
class Linklist                      
{
public:
    Linklist();                   //1.初始化一个单链表
    //~LinkList();                //删除一个单链表
    //"~"可以理解为与初始化相反,即删除(涉及到类中的析构函数,
    //与链表无太大关系,不在这赘述,主要我不会)
    //在销毁类中对应对象时使用,即销毁单链表时使用
    //但一般使用,故不要定义,直接定义删除函数就行
    void deleteLinklist();        //2.销毁单链表,大工程使用
    void clearLinlist();          //3.清空单链表,清空后可以使用,销毁后不可以
    void EstablishLinkList(int n);//4.创建一个单链表,n为长度
    void OutputLinkList();        //5.遍历线性表,即输出
    int GetLength();              //6.获取线性表长度
    bool IsEmpty();               //7.判断单链表是否为空
    node * Find(int data);        //8.查找节点,输出节点的位置
    void IEnd(int data);          //9.在尾部插入指定的元素
    void Insert(int data,int n);  //10.在指定位置插入指定元素
    void IHead(int data);         //11.在头部插入指定元素
    void DEnd();                  //12.在尾部删除元素
    void Delete(int data);        //13.删除指定的数据
    void DHead();                 //14.在头部删除数据
private:
    node * head;                  //定义私有变量--头结点
};

  • 类中定义的函数不一定要使用,但初始化和销毁的Linklist一定要用,不然会报错,所以最好 ~Linklist 不要定义,直接使用下面的销毁函数
  • 现在知道Linklist::Linklist的意思了吧,下面介绍第二种操作
操作二:销毁
void Linklist::deleteLinklist()
{
    struct node*p=head->next;
    while(p!=NULL)
    {
        struct node*tmp=p;
        p=p->next;
        free(tmp);
    }
    free(head);//释放头节点
}
  • 与之差不多的是不删除头节点的清空操作,唯一区别,是否释放了头节点
操作三:清空
void Linklist::clearLinklist()
{
    if(head==NULL)
    return ;
    struct node*p=head->next;
    while(p!=NULL)
    {
        struct node*tmp=p;
        p=p->next;
        free(tmp);
    }
    head->next=NULL;//本来head指向就是空,所以此句可有可无,最好带上,我不是太懂
}
  • 就像我们给数组赋值一样,要想给单链表赋值,只需要手写一个函数就行有如下操作
操作四:赋值(创建单链表)
void Linklist::EstablishLinklist(int n)//保证n>0
{
    node *pnew,*ptemp;//创建两个工作节点
    ptemp=head;
    for(int i=0;i<n;i++)
    {
        pnew=new node;//pnew在ptemp节点之后
        cin>>pnew->data;//从头插入每个节点的当前数据
        pnew->next=NULL;//新节点的下个地址为空
        ptemp->next=pnew;//将当前节点设为新节点
        ptemp=pnew;
    }
}
  • 疯狂的创建新节点与老节点建立联系就是链表的精髓
  • 就像我们输出数组元素一样,下面介绍手写的输出函数
操作五:遍历(输出单链表)
void Linklist::Output()
{
    if(head==NULL||head->next==NULL)
    {
        cout<<"链表为空"<<endl;
    }
    node *p=head;
    while(p->next!=NULL)
    {
        p=p->next;
        cout<<p->data<<" ";
    }
}
  • 输出没什么好说的从头开始往后输出就行
操作六:获取链表长度
  • 一看就懂代码奉上,不在赘述
int Linklist::GetLength()
{
    int count=0;
    node*p=head->next;
    while(p!=NULL)
    {
        count++;
        p=p->next;
    }
    return count;
}
操作七:判断线性表是否为空
  • 不看都懂,代码奉上,不在赘述
bool Linklist::IsEmpty()
{
    if(head->next==NULL)
    return true;
    else
    return false;
}
  • 有没有人想知道每个节点都是随机分配的那么它们存储在哪里呢,只要手写一个Find函数就能实现了
操作八:查找节点位置
node*Linklist::Find(int data)
{
    node*p=head;
    while(p->next!=NULL)
    {
        if(p->data==data)
        {
            return p;//不为空返回节点位置
        }
        p=p->next;
    }
    return NULL;    //为空返回空
}
  • Find函数要注意返回的是指针即位置!

下面讲述基操,就是删增等操作也就是链表的优点,终于到实用的地方了,心累,前面全是铺垫

增删元素o(1)是链表唯一的优点,那么老长的代码,终于到了它发挥作用的时候了

操作九:尾插
  • 如果为空直接加在头上,不为空则找到第一个空节点加在后面就行,代码奉上
void Linklist::IEnd(int data)
{
    node *newnode=new node;//定义一个节点
    newnode->next=NULL;
    newnode->data=data;//定义其数据与与指针域
    node*p=head;
    if(head==NULL)//如果空头,设其为头节点
    {
        head=newnode;
    }
    else
    {
        while(p->next!=NULL)//不空则找到第一个空节点放进该节点,即循环到最后一个节点将其放置在最后
        {
            p=p->next;
        }
        p->next=newnode;
    }
}
  • 有尾插必然少不了指插,咳咳!!
操作十:指插
  • 就多加了一个节点是否在定义域内,其余大差不差
void Linklist::Insert(int data,int n)
{
    if(n<1||n>GetLength())
    cout<<"值错误"<<endl;
    else
    {
        node*ptemp=new node;//定义新节点
        ptemp->data=data;    //给节点的数据域赋值
        node*p=head;        //从头遍历
        int i=1;
        while(n>i)
        {
            p=p->next;      //找到要插入的位置之前的位置p,遍历到指定位置
            i++;
        }
        ptemp->next=p->next;
        p->next=ptemp; //将p后的第一个位置给它,将新节点插入到指定位置
    }
}
操作十一:头插
void Linklist::IHead(int data)
{
    node*newnode=new node;
    newnode->data=data;
    node*p=head;
    if(head==NULL)
    {
        head=newnode;
    }
    newnode->next=p->next;
    p->next=newnode;
}
  • 不禁吟诗一首,尾插头插中间插大差不差……
  • 转眼到了操作12
操作十二:尾删
void Linklist::DEnd()
{
    node*p=head;
    node*ptemp=NULL;         //创建一个占位节点
    if(p->next==NULL)
    cout<<"链表为空"<<endl;
    else
    {
        while(p->next!=NULL)
        {
            ptemp=p;         //ptemp指向尾部的前一个节点
            p=p->next;       //找到要删除的p,循环到尾部的前一个
        }
        delete p;            //删除
        p=NULL;               //令P为空
        ptemp->next=NULL;    
    }
}

  • 同上面,有尾插指插头插就有尾删指删头删
操作十三:指删
void Linklist::Delete(int data)
{
    node*ptemp=Find(data);
    if(ptemp==head->next)
    {
        DHead();             //如果是第一个就删去头节点
    }
    else
    {
        node*p=head;
        while(p->next!=ptemp)
        {
            p=p->next;        //找到要删除节点的前一个位置
        }
        p->next=ptemp->next;//链接p与ptemp的下个节点把ptemp挤掉,即删除
        delete ptemp;//删除被挤掉的ptemp
        ptemp=NULL;//令为空
    }
}
  • 转眼间就说完了,花了我五六个小时,还有最后一步头删
操作十四:头删
void Linklist::DHead()
{
    node*p=head;
    if(p==NULL||p->next==NULL)
    cout<<"该链表为空"<<endl;
    else
    {
        node*ptemp=NULL;		//创建占位节点
        p=p->next;
        ptemp=p->next;   		//将头节点的下下个节点指向占位节点
        delete p;           //删去头节点
        p=NULL;
        head->next=ptemp;    //头节点的指针更换为占位节点的指针
    }
}
  • 好难好难,下面将完整不带注释的代码发出来,加油加油
#include<iostream>

using namespace std;

struct node//node是节点,每个节点存储一个数据和指向下个节点的指针
{
    int data;
    struct node* next;
};
//定义一个链表,并把需要的操作写在一个类中,方便使用
class Linklist
{
    
    public:
    Linklist();//操作一
    //~Linklist();
    void deleteLinklist();//操作二
    void clearLinklist();//操作三
    void EstablishLinklist(int n);//操作四
    void Output();//操作五
    int  GetLength();//操作六
    bool IsEmpty();//操作七
    node*Find(int data);//操作八
    
 //*****************************************************   
    
    void IEnd(int data);          //操作九、在尾部插入指定的元素
    void Insert(int data,int n);  //操作十、在指定位置插入指定元素
    void IHead(int data);         //操作11、在头部插入指定元素
    void DEnd();                  //操作12、在尾部删除元素
    void Delete(int data);        //操作13、删除指定的数据
    void DHead();                 //操作14、在头部删除指定元素

  //****************************************************

    private:
    node *head;//定义头节点
};

Linklist::Linklist()
{
    head=new node;
    head->data=0;
    head->next=NULL;
}

void Linklist::deleteLinklist()
{
    if(head==NULL)
    return ;
    struct node*p=head->next;
    while(p!=NULL)
    {
        struct node*tmp=p;
        p=p->next;
        free(tmp);
    }
    free(head);
}

void Linklist::clearLinklist()
{
    if(head==NULL)
    return ;
    struct node*p=head->next;
    while(p!=NULL)
    {
        struct node*tmp=p;
        p=p->next;
        free(tmp);
    }
    head->next=NULL;
}

void Linklist::EstablishLinklist(int n)
{
    node *pnew,*ptemp;
    ptemp=head;
    for(int i=0;i<n;i++)
    {
        pnew=new node;
        cin>>pnew->data;
        pnew->next=NULL;
        ptemp->next=pnew;
        ptemp=pnew;
    }
}
void Linklist::Output()
{
    if(head->next==NULL)
    {
        cout<<"链表为空"<<endl;
    }
    node *p=head;
    while(p->next!=NULL)
    {
        p=p->next;
        cout<<p->data<<" ";
    }
}

int Linklist::GetLength()
{
    int count=0;
    node*p=head->next;
    while(p!=NULL)
    {
        count++;
        p=p->next;
    }
    return count;
}

bool Linklist::IsEmpty()
{
    if(head->next==NULL)
    return true;
    else
    return false;
}

node*Linklist::Find(int data)
{
    node*p=head;
    while(p->next!=NULL)
    {
        if(p->data==data)
        {
            return p;
        }
        p=p->next;
    }
    return NULL;
}

void Linklist::IEnd(int data)
{
    node *newnode=new node;
    newnode->next=NULL;
    newnode->data=data;
    node*p=head;
    if(head==NULL)
    {
        head=newnode;
    }
    else
    {
        while(p->next!=NULL)
        {
            p=p->next;
        }
        p->next=newnode;
    }
}

void Linklist::Insert(int data,int n)
{
    if(n<1||n>GetLength())
    cout<<"值错误"<<endl;
    else
    {
        node*ptemp=new node;
        ptemp->data=data;    
        node*p=head;        
        int i=1;
        while(n>i)
        {
            p=p->next;      
            i++;
        }
        ptemp->next=p->next;
        p->next=ptemp; 
    }
}

void Linklist::IHead(int data)
{
    node*newnode=new node;
    newnode->data=data;
    node*p=head;
    if(head==NULL)
    {
        head=newnode;
    }
    newnode->next=p->next;
    p->next=newnode;
}

void Linklist::DEnd()
{
    node*p=head;
    node*ptemp=NULL;
    if(p->next==NULL)
    cout<<"链表为空"<<endl;
    else
    {
        while(p->next!=NULL)
        {
            ptemp=p;
            p=p->next;       
        }
        delete p;            
        p=NULL;               
        ptemp->next=NULL;    
    }
}

void Linklist::Delete(int data)
{
    node*ptemp=Find(data);
    if(ptemp==head->next)
    {
        DHead();
    }
    else
    {
        node*p=head;
        while(p->next!=ptemp)
        {
            p=p->next;        
        }
        p->next=ptemp->next;
        delete ptemp;
        ptemp=NULL;
    }
}

void Linklist::DHead()
{
    node*p=head;
    if(p==NULL||p->next==NULL)
    cout<<"该链表为空"<<endl;
    else
    {
        node*ptemp=NULL;
        p=p->next;
        ptemp=p->next;
        delete p;
        p=NULL;
        head->next=ptemp;
    }
}

int main()
{
    Linklist l;
    int n;cin>>n;
    l.EstablishLinklist(n);
    l.IEnd(6);
    l.Insert(6,3);
    l.IHead(6);
    l.Delete(6);
    l.Output();
    cout<<l.Find(1)<<endl;
    cout<<l.IsEmpty()<<endl;
}

  • 忘记写一个现在补上,删除指定位置的元素
void Linklist::Delete(int n)
{
    node*p=head;
    int i=1;
    while(n>i)
    {
        p=p->next;
        i++;
    }
    p->next=p->next->next;
}
  • 采用挤掉法
完工

Fighting

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值