C++模板实现链表

单链表是一种非常基本的数据结构. 虽然C++ STL中已经存在功能强大的List,但我们通过自己实现单链表,对于锻炼C++的基本功,加深对编程的理解与认识还是很有益的. 另外,自己的代码,在使用过程中更容易和敢于修改,更容易灵活定制自己的需求.
在实现单链表的过程中,选用模板,可以使得链表得到极大的灵活性.代码的可复用性大大增强.
核心代码分析解读:
1. 定义存放单个节点的数据结构: T可以在调用过程中灵活变换数据类型(基本数据类型,该程序的T不能支持对象数据类型). data为存放的数据, next为指向的下一个节点.
template struct LinkNode
{
T data;
LinkNode* next;
};
2.在添加节点时,我们只传入值.在函数内部构造节点.注意用new来分配内存.之后先将新节点的next指向node后面的节点(假定在node后面插入节点),然后将node的next指向新生成的节点.顺序很重要.
LinkNode *linkNode = new LinkNode();
linkNode->data = data;
linkNode->next = node->next;
node->next = linkNode;
3. 在删除时,需要准备要删除的前驱节点进行记录.是前驱节点指向后继节点.之后可以删除当前节点.注意释放内存,避免内存泄露.之后将指针指向NULL,避免野指针.
preNode->next = needRemoveNode->next;
delete needRemoveNode;
needRemoveNode = NULL;
4. 在对象释放的时候,C++会自动调用析构函数.在析构函数中,要记得释放内存,与将指针置NULL.
LinkNode *iter = head;
LinkNode *preIter = iter;
while (NULL != preIter->next)
{
iter = preIter->next;
preIter->next = iter->next;
cout << iter->data << ” will be deleted in destruct function.” << endl;
delete iter;
iter = NULL;
}
5. C++使用模板时,要注意在调用时,同时要包含.h与.cpp文件.或者将模板函数实现也写在.h文件中(双刃剑). 与通常只包含.h文件不同. 另外,要注意代码改动后,有时候需要进行进行全部重新编译,这个是因为模板在实例化时会产生二次编译,仅使用增量编译有时会产生错误.

程序运行结果如下图:

C++头文件如下:

#ifndef _LINK_LIST_H_
#define _LINK_LIST_H_


#include "Constant.h"


template<typename T> struct LinkNode
{
    T data;
    LinkNode* next;
};


template<typename T, const unsigned int capacity> class LinkList
{
public:
    LinkList();
    ~LinkList();
    bool isEmpty();
    bool isFull();
    bool insertFromHead(T data);
    bool insertAtLocation(T data, unsigned int n);
    bool deleteFromHead();
    bool deleteFromHead(T& data);
    bool deleteAtLocation(unsigned int n);
    bool deleteViaData(T data);
    bool getFirst(T& data);
    unsigned int getSize();
    void print();
private:
    unsigned int linkNodeNum;
    LinkNode<T> *head = NULL;
};


#endif // !_LINK_LIST_H_

C++源文件如下:

#include "LinkList.h"
#include <string>
#include <iostream>
using namespace std;




template<typename T, const unsigned int capacity> 
LinkList<T, capacity>::LinkList()
{
    linkNodeNum = 0;
    head = new LinkNode<T>;
    head->next = NULL;
    memset(head, 0, sizeof(head));
}


template<typename T, const unsigned int capacity> 
LinkList<T, capacity>::~LinkList()
{
    LinkNode<T> *iter = head;
    LinkNode<T> *preIter = iter;
    while (NULL != preIter->next)
    {       
        iter = preIter->next;
        preIter->next = iter->next;
        cout << iter->data << " will be deleted in destruct function." << endl;
        delete iter;
        iter = NULL;
    }
}


template<typename T, const unsigned int capacity> 
bool LinkList<T, capacity>::isEmpty()
{
    if (NULL == head->next)
        return true;
    return false;
}


template<typename T, const unsigned int capacity> 
bool LinkList<T, capacity>::isFull()
{
    if (capacity == linkNodeNum)
        return true;
    return false;
}


template<typename T, const unsigned int capacity> 
bool LinkList<T, capacity>::insertFromHead(T data)
{
    if (NULL == head)
    {
        head = new LinkNode<T>;
        head->next = NULL;
    }


    if (isFull())
    {
        return false;
    }


    LinkNode<T> *linkNode = new LinkNode<T>();
    linkNode->data = data;
    linkNode->next = NULL;
    LinkNode<T> *afterNode = head->next;
    head->next = linkNode;
    linkNode->next = afterNode;
    linkNodeNum++;
    return true;
}


//Insert data after nth node
template<typename T, const unsigned int capacity> 
bool LinkList<T, capacity>::insertAtLocation(T data, unsigned int n)
{
    if (isFull())
        return false;
    if (linkNodeNum < n)
    {
        return false;
    }
    else
    {
        //Insert after n
        LinkNode<T> *node = head;
        //Insert at last
        for (unsigned int i = 0; i < n; i++)
        {
            if (NULL != node->next)
            {
                node = node->next;
            }
            else
            {
                //need log the error
                return false;
            }
        }


        LinkNode<T> *linkNode = new LinkNode<T>();
        linkNode->data = data;
        linkNode->next = node->next;
        node->next = linkNode;
        linkNodeNum++;
    }
    return true;
}


template<typename T, const unsigned int capacity> 
bool LinkList<T, capacity>::deleteFromHead()
{
    bool rs = false;
    if (isEmpty())
    {
        rs = false;
    }
    else
    {
        LinkNode<T> *needRemoveNode = head->next;
        if (NULL == needRemoveNode)
        {
            rs = false;
        }
        else
        {
            LinkNode<T> *nextNode = needRemoveNode->next;
            head->next = nextNode;
            needRemoveNode->next = NULL;
            delete needRemoveNode;
            linkNodeNum--;
            rs = true;
        }
    }
    return rs;
}


template<typename T, const unsigned int capacity>
bool LinkList<T, capacity>::deleteFromHead(T& data)
{
    bool rs = false;
    if (isEmpty())
    {
        rs = false;
    }
    else
    {
        LinkNode<T> *needRemoveNode = head->next;
        if (NULL == needRemoveNode)
        {
            rs = false;
        }
        else
        {
            data = needRemoveNode->data;
            LinkNode<T> *nextNode = needRemoveNode->next;
            head->next = nextNode;
            needRemoveNode->next = NULL;
            delete needRemoveNode;
            linkNodeNum--;
            rs = true;
        }
    }
    return rs;
}


template<typename T, const unsigned int capacity> 
bool LinkList<T, capacity>::deleteAtLocation(unsigned int n)
{
    if (isEmpty())
    {
        return false;
    }
    if (n > linkNodeNum)
    {
        return false;
    }
    else
    {
        LinkNode<T> *needRemoveNode = head;
        LinkNode<T> *preNode = NULL;
        for (unsigned int i = 0; i < n; i++)
        {
            preNode = needRemoveNode;
            needRemoveNode = needRemoveNode->next;
            if (NULL == needRemoveNode)
            {
                return false;
            }
        }
        preNode->next = needRemoveNode->next;
        delete needRemoveNode;
        needRemoveNode = NULL;
        linkNodeNum--;
    }
    return true;
}


template<typename T, const unsigned int capacity> 
bool LinkList<T, capacity>::deleteViaData(T data)
{
    if (isEmpty())
    {
        return false;
    }
    bool isFind = false;
    LinkNode<T> *iter = head;
    while(NULL != iter->next)
    {
        LinkNode<T> *preNode = iter;
        iter = iter->next;
        try
        {
            if (data == iter->data)
            {
                preNode->next = iter->next;
                delete iter;
                iter = NULL;
                isFind = true;
                linkNodeNum--;
                break;
            }
        }
        catch (exception e)
        {
            cout << e.what() << endl;
            return false;
        }
    }
    return isFind;
}


template <typename T, const unsigned int capacity>
bool LinkList<T, capacity>::getFirst(T& data)
{
    bool rs = false;
    if (isEmpty())
    {
        rs = false;
    }
    else
    {
        if ((NULL == head) || (NULL == head->next))
        {
            rs = false;
        }
        else
        {
            data = head->next->data;
            rs = true;
        }
    }
    return rs;
}


template<typename T, const unsigned int capacity>
unsigned int LinkList<T, capacity>::getSize()
{
    return linkNodeNum;
}


template<typename T, const unsigned int capacity> 
void LinkList<T, capacity>::print()
{
    LinkNode<T>* iter = head;
    while (NULL != iter->next)
    {
        iter = iter->next;
        cout << iter->data << "  ";
    }
    cout << endl;


}

测试代码如下:

void testLinkList()
{
    LinkList<int,LINK_NODE_SIZE> *linkList = new LinkList<int, LINK_NODE_SIZE>();
    linkList->insertFromHead(9);
    linkList->print();
    linkList->insertFromHead(7);
    linkList->print();
    linkList->insertAtLocation(8, 1);
    linkList->print();
    linkList->insertAtLocation(6, 8);
    linkList->print();
    linkList->insertAtLocation(5, 3);
    linkList->print();
    linkList->insertFromHead(4);
    linkList->print();
    linkList->insertFromHead(3);
    linkList->print();
    linkList->deleteFromHead();
    linkList->print();
    linkList->deleteViaData(7);
    linkList->print();
    linkList->deleteAtLocation(3);
    linkList->print();
    linkList->deleteAtLocation(14);
    linkList->print();
    linkList->deleteViaData(0);
    linkList->print();
    linkList->deleteViaData(1.2);
    linkList->print();
    delete linkList;
    linkList = NULL;
}


void testLinkList2()
{
    LinkList<string, LINK_NODE_SIZE> *linkList = new LinkList<string, LINK_NODE_SIZE>();
    linkList->insertFromHead("AA");
    linkList->print();
    linkList->insertFromHead("BB");
    linkList->print();
    linkList->insertAtLocation("CC", 1);
    linkList->print();
    linkList->insertAtLocation("DD", 8);
    linkList->print();
    linkList->insertAtLocation("EE", 3);
    linkList->print();
    linkList->insertFromHead("FF");
    linkList->print();
    linkList->insertFromHead("GG");
    linkList->print();
    linkList->deleteFromHead();
    linkList->print();
    linkList->deleteViaData("FF");
    linkList->print();
    linkList->deleteAtLocation(3);
    linkList->print();
    linkList->deleteAtLocation(14);
    linkList->print();
    linkList->deleteViaData("DDD");
    linkList->print();
    delete linkList;
    linkList = NULL;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
面向对象程序设计课程作业 1. 请创建一个数据类型为T的链表模板List,实现以下成员函数: 1) 默认构造函数List(),将该链表初始化为一个空链表(10分) 2) 拷贝构造函数List(const List& list),根据一个给定的链表构造当前链表(10分) 3) 析构函数~List(),释放链表中的所有节点(10分) 4) Push_back(T e)函数,往链表最末尾插入一个元素为e的节点(10分) 5) operator<<()友元函数,将链表的所有元素按顺序输出(10分) 6) operator=()函数,实现两个链表的赋值操作(10分) 7) operator+()函数,实现两个链表的连接,A=B+C(10分) 2. 请编写main函数,测试该类模板的正确性: 1) 用List模板定义一个List类型的模板类对象int_listB,从键盘读入m个整数,调用Push_back函数将这m个整数依次插入到该链表中;(4分) 2) 用List模板定义一个List类型的模板类对象int_listC,从键盘读入n个整数,调用Push_back函数将这n个整数依次插入到该链表中;(4分) 3) 用List模板定义一个List类型的模板类对象int_listA,调用List的成员函数实现A = B + C;(4分) 4) 用cout直接输出int_listA的所有元素(3分) 5) 用List模板定义List类型的模板类对象double_listA, double_listB, double_listC,重复上述操作。(15分) 3. 输入输出样例: 1) 输入样例 4 12 23 34 45 3 56 67 78 3 1.2 2.3 3.4 4 4.5 5.6 6.7 7.8 2) 输出样例 12 23 34 45 56 67 78 1.2 2.3 3.4 4.5 5.6 6.7 7.8

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值