c++链表

主函数文件:
#include <iostream>

#include "list_t.h"
using namespace std;

int main()
{
    list_t lin;    // 定义类对象 lin

    lin.append(3);  //
    lin.append(4);
    lin.append(7);
    lin.append(67);
    lin.append(98);
    lin.append(23);
    lin.insertHead(1998);

    cout << lin;  //输出类对象lin

    lin.delNode(67);

    cout << lin;

    lin.delNode(23);

    cout << lin;
    //lin.delNode(&lin);
    lin.find(2);

    cout << "Hello World! "; 
}
类与函数声明及函数实现文件
#pragma once

#include <iostream>  //输出重载时调用
using namespace std;

struct  list_node  //双向链表元素结构体
{
    int data;            //***元素数据,用于存储数据***
    list_node *next;        //
$元素指针,访问节点,对数据进行操作
$元素指针,访问节点,对数据进行操作
$
    list_node *prev;
};

class list_t  //类的定义,用类来实现对链表数据的操作
{
private:
    int size;          //私用的三个类变量:链表元素个数,前一个元素结构体指针,后一个元素结构体指针
    list_node * head; 
    list_node * tail;
public:
    list_t(void);   //类构造函数和析构函数
    ~list_t(void);

    //声明类成员函数之一:判断要操作的链表是否为空(是否没有元素)
    bool isEmpty(void);

    //声明类成员函数之二三:对链表的头插与尾插
    int insertHead(int d);
    int append(int d);

    //声明类成员函数之四五:对链表中指定的元素与指定的数据进行删除
    int delNode(list_node * node);
    int delNode(int d);

    //声明类成员函数之六: 对链表中的指定数据进行查找
    list_node * find(int d);

    //声明类的友元输出运算符重载函数,
    friend ostream & operator<<(ostream & out, const list_t & li);
};

//实现类构造函数和析构函数
list_t::list_t(void)
{
    head = tail = NULL;  //初始化(清空)链表的元素及元素个数
    size = 0;
}

list_t::~list_t(void)
{
}

//实现类成员函数之一:判断要操作的链表是否为空(是否没有元素)
bool list_t::isEmpty(void)
{
    if(0 == size)  
    {
        return true;
    }
    return false;
}
//实现类成员函数之二三:对链表的头插与尾插

int list_t::insertHead(int d)  //元素头插, 入参为一个整型数据
{
    list_node * li = new list_node;  //1,定义并开辟链表指针 "li",给确定无疑的东西赋值处理
    li->data = d;  //!!!通过链表得元素中数据赋值,也可写为
(∗li).data=d;
(∗li).data=d;
$$$
    li->prev = NULL;
    //2,其次,当遇到简单的情况下,我们该怎么办?
    //当链表为空时
    if (isEmpty())
    {
        head = tail = li;  //***给两个链表结构体指针(类内变量)进行 li的内存拷贝
        size++;    //元素个数加1
        return size;   //返回元素个数
    }
    //3,最后,遇到非简单的情况下我们又该怎么做?
    //当链表不为空时
    li->next = head;   //头部插入元素的后向指针 变为 原链表头部结构体元素地址
    head->prev = li;   //原链表头部结构体元素的前向指针变为 头插插入的元素 li

    head = li;   //更新原链表头部结构体元素为 头插插入的元素 li
    size++;  //元素个数加1
    return size;  //返回元素个数
}

int list_t::append(int d)  //元素尾插, 入参为一个整型数据
{
    list_node * li = new list_node;  //1,定义并开辟链表指针 "li",给确定无疑的东西赋值处理
    (*li).data = d;  //!!!通过链表得元素中数据赋值,也可写为
li−>data=d;
li−>data=d;
$$$
    li->next = NULL;  //尾部插入元素的后向指针显然是NULL,指向为空
    //2,其次,当遇到简单的情况下,我们该怎么办?
    //当链表为空时
    if (isEmpty())  //???很奇怪,形参写入为void时报错,不写入时正确.
    {
        head = tail = li;  //***给两个链表结构体指针(类内变量)进行 li 的内存拷贝
        li->prev = NULL;  //链表元素的前向指针赋值为空指针,因为现在的情况是该表中只有他一个元素!!!我们常常会忘掉前提条件
        size++;  //链表元素个数加1
        return size;  //返回链表元素个数
    }
    //3,最后,遇到非简单的情况下我们又该怎么做?
    //当链表不为空时
    tail->next = li;  //(类内保存的)原链表尾部结构体元素的后向指针 更新为 li (打扫屋子)
    li->prev = tail;  //尾部插入元素的前向指针 变为 原链表尾部结构体元素的指针
    
    tail = li;  //将 原链表尾部结构体元素 更新为 新尾部插入的元素
    size++;  //元素个数加1
    return size;  //返回元素个数
}

////声明类成员函数之四五:对链表中指定的元素与指定的数据进行删除
//int list_t::delNode(list_node * node)  //删除链表的一个结点(形参为该结点的地址)
//{
//    if (isEmpty())  //若是空表则不删除
//    {
//        return 0;
//    }
//
//    list_node * tmp = head;  //若不是空表,则内存拷贝一份头元素 命名为 tmp
//    while (tmp)
//    {
//        if (tmp->data != node->data)  //依据该结点的数据来遍历寻找这个结点(这不对,要是表中有至少两个元素数据一样就会产生误操作)
//        {
//            tmp = tmp->next;  //遍历移位找出要删除的结点tmp
//            continue;
//        }
//
//        if (head == tmp)  //1.若要删除的结点是头结点时
//        {
//            head = head->next;  //新的头结点就成为了 原头结点的后向指针
//            head->prev = NULL;  //新头结点的前向指针 变为 NULL
//            delete tmp;  //删除结点(释放指针的指向->变为随机地址值->变成野指针->危险(应处理为NULL))
//            tmp = NULL;
//            size--;  //元素个数减1
//            break;
//        }
//
//        if (tmp == tail)  //若要删除的结点是尾结点时
//        {
//            tail = tail->prev;  //新尾结点就成为了 原尾结点的前向结点
//            tail->next = NULL;  //新尾结点的后向指针 变为 NULL
//            delete tmp;  //删除结点(释放指针的指向->变为随机地址值->变成野指针->危险(应处理为NULL))
//            tmp = NULL;
//
//            size--;  //元素个数减1
//            break;
//        }
//        //2.若要删除的结点时中间结点时
//        tmp->prev->next = tmp->next;  //要删除结点的前1个结点的后向指针 指向 要删除结点的后1个结点
//        tmp->next->prev = tmp->prev;  //要删除结点的后1个结点的前向指针 指向 要删除结点的前1个结点
//
//        delete tmp;  //删除结点
//        tmp = NULL;
//        size--;
//        break;
//    }
//    return size;  //返回链表元素个数
//}

int list_t::delNode(int d)  //删除链表的一个结点(形参为该结点的数据),同上面一样
{
    if (isEmpty())  
    {
        return 0;
    }

    list_node * tmp = head;  

    while (tmp)
    {
        if (tmp->data != d)
        {
            tmp = tmp->next;
            continue;
        }

        if (head == tmp)
        {
            head = head->next;
            head->prev = NULL;
            delete tmp;
            tmp = NULL;
            size--;
            break;
        }

        if (tmp == tail)
        {
            tail = tail->prev;
            tail->next = NULL;
            delete tmp;
            size--;
            break;
        }

        tmp->prev->next = tmp->next;
        tmp->next->prev = tmp->prev;

        delete tmp;
        tmp = NULL;
        size--;
        break;
    }
    return size;
}
//实现类成员函数之六: 对链表中的指定数据进行查找
list_node * list_t::find(int d)
{
    if (isEmpty())
    {
        return NULL;
    }

    list_node * tmp = head;  //从头开始遍历查找,找到后返回元素指针,找不到则返回尾指针
    while (tmp)
    {
        if (tmp->data == d)
        {
            break;
        }
        tmp = tmp->next;
    }

    return tmp;
}

//实现类的友元输出运算符重载函数,
ostream & operator<<(ostream & out, const list_t & li)
{
    list_node * tmp = li.head;  //从头遍历输出

    out << "list content:"<<endl;
    while (tmp)
    {
        out << tmp->data << " ";
        tmp = tmp->next;
    }
    out << endl;

    return out;
}
---------------------

原文地址:https://www.cnblogs.com/-lhy-to-s/p/10664911.html