数据结构与算法——单向链表ADT(C++)

该单向链表类名字为Linked_list。

1.Linked_list类的基本数据成员:

        单向链表类Linked_list的基本数据成员包括:指向链表头节点的指针head,以及链表的节点数目size,如下所示:

Node *head;                                                 //当前链表的头节点
int size;                                                   //当前链表的节点数目  

        其中链表节点Node类的实现如下:

struct Node
{
    int data;
    Node *next=NULL;
    Node(int nums):data(nums),next(NULL)
    {
    }
};

2.Linked_list类的成员函数:

        Linked_list类的成员函数如下:

    //构造函数
    Linked_list();                                              //单向链表构造函数:构造空链表
    Linked_list(int nums[],int size);                           //单向链表构造函数:由数组构造链表
    Linked_list(const Linked_list &other);                      //拷贝构造函数
    //运算符
    Linked_list operator= (const Linked_list &other);           //拷贝构造运算符
    Linked_list operator+ (const Linked_list &other);           //加法运算符:将两个单向链表相连接
    //链表节点查找
    Node *search_by_content(int target);                        //根据内容查找节点的第一次出现的地址
    int search_by_position(int pos);                            //根据下标位置查找节点的内容
    //链表节点插入
    bool insert_by_position(int nums,int pos);                  //根据位置进行插入节点
    void insert_back(int nums);                                 //将指定的内容插入到链表的末尾
    //链表节点删除
    bool delete_by_content(int nums);                           //根据内容进行删除节点
    bool delete_by_position(int pos);                           //根据位置进行删除节点
    //单向链表特殊操作
    void reverse();                                             //将当前的链表反转
    void clean();                                               //将当前链表清空
    int count();                                                //返回当前链表的节点数目
    void print();                                               //输出链表的值


3.Linked_list类成员函数的实现:

Linked_list类成员函数的实现,实现的细节和需要注意的要点可以参见注释:

Linked_list::Linked_list()                        //单向链表构造函数:构造空链表
{
    size=0;
    head=NULL;
}

Linked_list::Linked_list(int nums[],int isize)     //单向链表构造函数:由数组构造链表
{
    //该函数既可以通过调用insert_back进行实现,也可以不调用
    //若决定调用insert_back成员函数进行实现,则必须先初始化head=NULL,size=0,因为insert_back函数需要链表的相关信息
    head=NULL;
    size=0;
    for(int i=0;idata);    //该函数已经计算了链表节点数目
        now=now->next;
    }
}

Linked_list Linked_list::operator= (const Linked_list &other)         //拷贝构造运算符
{
    //链表的拷贝构造运算符需要考虑原链表是否为空,原链表非空的时候需要清空链表
    if(size)               //当原链表非空的时候,这时需要将原链表清空,否则会导致内存泄漏
    (*this).clean();    
    Node *now=other.head;
    while(now!=NULL)
    {
        (*this).insert_back(now->data);
        now=now->next;
    }      
    size=other.size;
    return (*this);
}

Linked_list Linked_list::operator+ (const Linked_list &other)         //加法运算符:将两个单向链表相连接
{
    Node *now=other.head;
    while(now!=NULL)
    {
        (*this).insert_back(now->data);
        now=now->next;
    }
    size+=other.size;
    return (*this);
}

Node *Linked_list::search_by_content(int target)                          //给定内容查找该内容所在的节点
{
    Node *now=head;
    while(now!=NULL)
    {
        if(now->data==target)
        return now;
        now=now->next;
    }
    return NULL;
}

int Linked_list::search_by_position(int pos)                            //根据下标位置查找节点的内容
{
    if(pos>=size)
    return INT_MAX;    //下标超出上限返回错误标志INT_MAX
    if(pos<0)
    return INT_MIN;    //下标超出下限返回错误标志INT_MAX
    Node *now=head;
    for(int i=0;inext;
    }
    return now->data;
}

bool Linked_list::insert_by_position(int nums,int pos)                               //根据位置进行插入节点
{
    //先判断插入位置是否合法
    if(pos>size||pos<0)
    return false;
    //特判:当pos=0,即插入的节点位置为链表头时,这里已经特别考虑了链表为空时在链表头插入的情况
    else if(!pos)
    {
        Node *temp=head;
        head=new Node(nums);
        head->next=temp; 
    }
    //特判:当pos=size,即插入的节点位置为链表尾时
    else if(pos==size)
    {
        Node *now=head;
        while(now->next)
        {
            now=now->next;
        }
        now->next=new Node(nums);
    }
    else 
    {
        Node *back=head;
        for(int i=0;inext;
        }
        Node *now=new Node(nums);
        Node *next=back->next;
        back->next=now;
        now->next=next;
    }
    size++;
    return true;
}

void Linked_list::insert_back(int nums)                                  //将指定的内容插入到链表的末尾
{
    //特判:当链表为空的时候,需要特别进行处理
    if(head==NULL)
    {
        head=new Node(nums);
    }
    else
    {
        Node *now=head;
        while(now->next)
        {
            now=now->next;
        }
        now->next=new Node(nums);
    }
    size++;
}

bool Linked_list::delete_by_content(int nums)                   //根据内容进行删除节点
{
    bool flag=false;  
    Node *now=head;
    while(now)
    {
        if(now->data==nums)
        {
            flag=1;
            //下面开始删除节点
            if(now==head)      //特判情况:当待删除的节点是链表的第一个节点
            {
                Node *pre_del=head;
                head=now;
                size--;
                delete pre_del;
            }
            else              //其他情况:当待删除的节点不是链表的第一个节点   
            {
                //先查找待删除节点的前驱元
                Node *back=head;
                while(back->next!=now)
                {
                    back=back->next;
                }
                //开始正式删除待删除节点
                back->next=now->next;
                Node *pre_del=now;
                size--;
                delete pre_del;
            }
        }
        now=now->next;       //推荐将游标移动语句now=now->next写在链表的
    }
    return flag;
}

bool Linked_list::delete_by_position(int pos)                   //根据位置进行删除节点
{
    //这里使用双游标法减少运行时间,思路:空间换时间
    if(pos<0||pos>=size)
    return false;
    else if(pos==0)             //特判:删除头节点情况
    {
        if(size==1)             //特判:当链表中只剩下一个节点的情况
        {
            delete head;
            head=NULL;
            size=0;
        }
        else
        {
            Node *pre_del=head;
            head=head->next;
            size--;
            delete pre_del;
        }
    }
    else
    {
        Node *back=head;
        Node *now=head->next;
        for(int i=0;inext;
            now=now->next;
        }
        back->next=now->next;
        size--;
        delete now;
    }
    return true;
}

void Linked_list::reverse()                                             //将当前的链表反转
{
    //常用的一种链表反转方式:使用双指针将各个节点的连接处进行反转
    if(head==NULL)   //特判:空链表不需要进行反转
    return;
    Node *back=head;
    Node *now=head->next;
    while(now)
    {
        Node *temp=now->next;   //记录指针移动的下一个节点
        //反转连接处
        now->next=back;
        //移动双指针
        back=now;         
        now=temp;
    }
    //在每个连接处都进行反转之后,这时双指针中的back即为新的链表头节点
    //这时先将链表尾节点(即原链表头)的next指针置为空
    head->next=NULL;
    head=back;
    return;
}

void Linked_list::clean()                                               //将当前链表清空
{
    Node *now=head;
    while(now)
    {
        Node *temp=now;
        now=now->next;
        delete temp;
    }
    size=0;
    head=NULL;
}

int Linked_list::count()                                                //返回当前链表的节点数目
{
    return size;
}

void Linked_list::print()                                               //输出链表各节点的值
{ 
    Node *now=head;
    while(now)
    {
        cout<data<<" ";
        now=now->next;
    }
    cout<

4.ADT源代码:

#include 
#include 

using namespace std;

struct Node
{
    int data;
    Node *next=NULL;
    Node(int nums):data(nums),next(NULL)
    {
    }
};

class Linked_list
{
    public:
    //构造函数
    Linked_list();                                              //单向链表构造函数:构造空链表
    Linked_list(int nums[],int size);                           //单向链表构造函数:由数组构造链表
    Linked_list(const Linked_list &other);                      //拷贝构造函数
    //运算符
    Linked_list operator= (const Linked_list &other);           //拷贝构造运算符
    Linked_list operator+ (const Linked_list &other);           //加法运算符:将两个单向链表相连接
    //链表节点查找
    Node *search_by_content(int target);                        //根据内容查找节点的第一次出现的地址
    int search_by_position(int pos);                            //根据下标位置查找节点的内容
    //链表节点插入
    bool insert_by_position(int nums,int pos);                  //根据位置进行插入节点
    void insert_back(int nums);                                 //将指定的内容插入到链表的末尾
    //链表节点删除
    bool delete_by_content(int nums);                           //根据内容进行删除节点
    bool delete_by_position(int pos);                           //根据位置进行删除节点
    //单向链表特殊操作
    void reverse();                                             //将当前的链表反转
    void clean();                                               //将当前链表清空
    int count();                                                //返回当前链表的节点数目
    void print();                                               //输出链表的值
    private:
    Node *head;                                                 //当前链表的头节点
    int size;                                                   //当前链表的节点数目    
};

Linked_list::Linked_list()                        //单向链表构造函数:构造空链表
{
    size=0;
    head=NULL;
}

Linked_list::Linked_list(int nums[],int isize)     //单向链表构造函数:由数组构造链表
{
    //该函数既可以通过调用insert_back进行实现,也可以不调用
    //若决定调用insert_back成员函数进行实现,则必须先初始化head=NULL,size=0,因为insert_back函数需要链表的相关信息
    head=NULL;
    size=0;
    for(int i=0;idata);    //该函数已经计算了链表节点数目
        now=now->next;
    }
}

Linked_list Linked_list::operator= (const Linked_list &other)         //拷贝构造运算符
{
    //链表的拷贝构造运算符需要考虑原链表是否为空,原链表非空的时候需要清空链表
    if(size)               //当原链表非空的时候,这时需要将原链表清空,否则会导致内存泄漏
    (*this).clean();    
    Node *now=other.head;
    while(now!=NULL)
    {
        (*this).insert_back(now->data);
        now=now->next;
    }      
    size=other.size;
    return (*this);
}

Linked_list Linked_list::operator+ (const Linked_list &other)         //加法运算符:将两个单向链表相连接
{
    Node *now=other.head;
    while(now!=NULL)
    {
        (*this).insert_back(now->data);
        now=now->next;
    }
    size+=other.size;
    return (*this);
}

Node *Linked_list::search_by_content(int target)                          //给定内容查找该内容所在的节点
{
    Node *now=head;
    while(now!=NULL)
    {
        if(now->data==target)
        return now;
        now=now->next;
    }
    return NULL;
}

int Linked_list::search_by_position(int pos)                            //根据下标位置查找节点的内容
{
    if(pos>=size)
    return INT_MAX;    //下标超出上限返回错误标志INT_MAX
    if(pos<0)
    return INT_MIN;    //下标超出下限返回错误标志INT_MAX
    Node *now=head;
    for(int i=0;inext;
    }
    return now->data;
}

bool Linked_list::insert_by_position(int nums,int pos)                               //根据位置进行插入节点
{
    //先判断插入位置是否合法
    if(pos>size||pos<0)
    return false;
    //特判:当pos=0,即插入的节点位置为链表头时,这里已经特别考虑了链表为空时在链表头插入的情况
    else if(!pos)
    {
        Node *temp=head;
        head=new Node(nums);
        head->next=temp; 
    }
    //特判:当pos=size,即插入的节点位置为链表尾时
    else if(pos==size)
    {
        Node *now=head;
        while(now->next)
        {
            now=now->next;
        }
        now->next=new Node(nums);
    }
    else 
    {
        Node *back=head;
        for(int i=0;inext;
        }
        Node *now=new Node(nums);
        Node *next=back->next;
        back->next=now;
        now->next=next;
    }
    size++;
    return true;
}

void Linked_list::insert_back(int nums)                                  //将指定的内容插入到链表的末尾
{
    //特判:当链表为空的时候,需要特别进行处理
    if(head==NULL)
    {
        head=new Node(nums);
    }
    else
    {
        Node *now=head;
        while(now->next)
        {
            now=now->next;
        }
        now->next=new Node(nums);
    }
    size++;
}

bool Linked_list::delete_by_content(int nums)                   //根据内容进行删除节点
{
    bool flag=false;  
    Node *now=head;
    while(now)
    {
        if(now->data==nums)
        {
            flag=1;
            //下面开始删除节点
            if(now==head)      //特判情况:当待删除的节点是链表的第一个节点
            {
                Node *pre_del=head;
                head=now;
                size--;
                delete pre_del;
            }
            else              //其他情况:当待删除的节点不是链表的第一个节点   
            {
                //先查找待删除节点的前驱元
                Node *back=head;
                while(back->next!=now)
                {
                    back=back->next;
                }
                //开始正式删除待删除节点
                back->next=now->next;
                Node *pre_del=now;
                size--;
                delete pre_del;
            }
        }
        now=now->next;       //推荐将游标移动语句now=now->next写在链表的
    }
    return flag;
}

bool Linked_list::delete_by_position(int pos)                   //根据位置进行删除节点
{
    //这里使用双游标法减少运行时间,思路:空间换时间
    if(pos<0||pos>=size)
    return false;
    else if(pos==0)             //特判:删除头节点情况
    {
        if(size==1)             //特判:当链表中只剩下一个节点的情况
        {
            delete head;
            head=NULL;
            size=0;
        }
        else
        {
            Node *pre_del=head;
            head=head->next;
            size--;
            delete pre_del;
        }
    }
    else
    {
        Node *back=head;
        Node *now=head->next;
        for(int i=0;inext;
            now=now->next;
        }
        back->next=now->next;
        size--;
        delete now;
    }
    return true;
}

void Linked_list::reverse()                                             //将当前的链表反转
{
    //常用的一种链表反转方式:使用双指针将各个节点的连接处进行反转
    if(head==NULL)   //特判:空链表不需要进行反转
    return;
    Node *back=head;
    Node *now=head->next;
    while(now)
    {
        Node *temp=now->next;   //记录指针移动的下一个节点
        //反转连接处
        now->next=back;
        //移动双指针
        back=now;         
        now=temp;
    }
    //在每个连接处都进行反转之后,这时双指针中的back即为新的链表头节点
    //这时先将链表尾节点(即原链表头)的next指针置为空
    head->next=NULL;
    head=back;
    return;
}

void Linked_list::clean()                                               //将当前链表清空
{
    Node *now=head;
    while(now)
    {
        Node *temp=now;
        now=now->next;
        delete temp;
    }
    size=0;
    head=NULL;
}

int Linked_list::count()                                                //返回当前链表的节点数目
{
    return size;
}

void Linked_list::print()                                               //输出链表各节点的值
{ 
    Node *now=head;
    while(now)
    {
        cout<data<<" ";
        now=now->next;
    }
    cout<data<data<



你可能感兴趣的:(数据结构和算法)