自定义的模板化数据结构(1)

简介

  1. 链表
    “排列在一行”的数据项的集合——在链表中的任何一个数据项上都可以进行插入和删除操作
  2. 堆栈(区分数据结构中的堆栈与存储结构中的堆和栈)
    是编译器和操作系统中重要的数据结构:元素的插入和删除只能在堆栈的一端——栈顶进行。
  3. 队列
    插入操作在队尾进行,删除操作在队列头进行,FIFO。
  4. 二叉树
    便于数据搜索和排序,去重,以及把表达式编译为机器语言。

如果可以,始终倾向于标准库的容器、迭代器和算法。

自引用类

一个自引用类包含一个指向与它同类的对象的指针成员

class Node
{
public:
	explicit Node(int);
	void setData(int) const;
	int getData();
	void setNextPtr(Node *);
	Node* getNextPtr() const;
private:
	int data;
	Node* nextPtr;
}

自引用类对象链接在一起组成链表、队列、堆栈、树等。

链表

一个自引用类对象的线性集合,其中的对象称为节点(node),通过指针链链接。
节点在内存中通常不是连续存储,逻辑上可以看成是连续的.
单向链表
循环单向链表
双向链表
循环双向链表

//***********************单向链表节点模板类*****************************
#ifndef LISTCODE_H
#define LISTCODE_H

template <typename NODETYPE>
class List;                                 //前置声明,告诉ListNode 有一个List类,即使它尚未定义,这样可以将它声明为友元声明

template <typename NODETYPE>
class ListNode
{
    friend class List<NODETYPE>;            //声明为友类,便于List对象操作该类成员,提高性能

public:
    explicit ListNode(const NODETYPE& info):data(info),nextPtr(nullptr){}
    NODETYPE getData() const{               // 获取数据
    return data;
    }

private:
    NODETYPE data;
    ListNode<NODETYPE> *nextPtr;
};
// 单链表示例
#ifndef LIST_H
#define LIST_H

#include <iostream>
#include "ListNode.h"

template < typename NODETYPE >
class List
{
public:
    List() : firstPtr(nullptr),lastPtr(nullptr)
    {

    }
    ~List()
    {
        if(!isempty())
        {
			std::cout << "Destroying nodes...\n";

            ListNode<NODETYPE> *currentPtr = firstPtr;
            ListNode<NODETYPE> *tempPtr = nullptr;
            while(currentPtr !=nullptr)
            {
                template = currentPtr;
                std::cout << tempPtr->data << '\n';
                currentPtr = currentPtr->nextPtr;
                delete tempPtr;
            }
        }
        std::cout << "All nodes destroyed.\n\n";
    }

    void inserAtFront(const NODETYPE& info)        // 前端插入
    {
        ListNode<NODETYPE> *newPtr = getNewNode(info);
        if (isempty())
        {
            firstPtr = lastPtr = newPtr;           //可以连续赋值
        }
        else
        {
            newPtr->nextPtr = firstPtr;
            firstPtr = newPtr;
        }
    }

    void insertAtBack(const NODETYPE& info)        //后端插入
    {
        ListNode<NODETYPE> *newPtr = getNewNode(onfo);
        if (isempty())
        {
            lastPtr = firstPtr = newPtr;           //可以连续赋值
        }
        else
        {
            lastPtr->nextPtr = newPtr;
            lastPtr = newPtr;
        }
    }

    bool removeFromFront(NODETYPE&value)   // 从前端删除,被删除Node的值传给value,返回bool值。
    {
        if(isempty())
        {
            std::cout << "List is already empty,cannot remove.\n" ;
            return false;
        }
        else
        {
            ListNode<typename NODETYPE> *temp = firstPtr;
            if(firstPtr == lastPtr)
                firstPtr == lastPtr = nullptr;
            else
                firstPtr = firstPtr->nextPtr;

            value = firstPtr->data;
            delete temp;
            return true;
        }
    }

    bool removeFromBack(NODETYPE&value)   // 从后端删除,被删除Node的值传给value,返回bool值。
    {
        if(isempty())
        {
            std::cout << "List is already empty,cannot remove.\n" ;
            return false;
        }
        else
        {
            ListNode<typename NODETYPE> *temp = lastPtr;
            if(firstPtr == lastPtr)
            {
                firstPtr == lastPtr = nullptr;
            }   
            else
            {
                ListNode<typename NODETYPE> *p = firstPtr;
                while(p->nextPtr != lastPtr)
                {
                    p = p->nextPtr;
                }
                lastPtr = p;
            }
            value = temp->data;
            delete temp;
            return true;
        }
    }

    bool isempty() const
    {
        return firstPtr == nullptr;
    }



private:
    ListNode<NODETYPE> * firstPtr;
    ListNode<NODETYPE> *lastPtr;

    ListNode<NODETYPE> * getNewNode(const NODETYPE&value)
    {
        return new ListNode<NODETYPE>(value);       //创建一个动态内存区存储一个ListNode对象,返回对象地址
    }
};

#endif

堆栈

堆栈数据结构允许在堆栈顶部增加和删除节点,是FIFO数据结构。
一种实现的方法是将它作为一种有限制链表。
主要成员函数 push 压栈,pop 出栈。

堆栈的作用

  1. 函数调用,储存调用者变量和返回地址
  2. 函数返回调用者或抛出一个异常时,每个局部对象的析构函数(如果有)被调用,该函数的自动变量的空间出栈,变量销毁
  3. 在编译器中用来计算表达式和生成机器指令

基于List继承实现类模板Stack

// *************基于List模板的Stack类模板实现

#ifndef STACK_H
#define STACK_H
#include "List.h"

template <typename STACKTYPE>
class Stack :private List<STACKTYPE>   //private继承,使得所有List成员函数在Stack中都是私有,只调需要的基类成员函数,其余的对外隐藏
{
    public:
        void push(const STACKTYPE& data)
        {
            insertFromFront(data);
        }
        void pop()
        {
            removeFromFront(STACKTYPE& data);
        }
        bool isStackEmpty() const
        {
            return this->isempty();   // 模板的特化才能解析出成员函数标识符名称,依赖于参数,没有参数的成员函数必须显式使用this指针。
        }
};
#endif

isStackEmpty() 需要显式使用this指针,这样编译器可正确区分 模板中定义的标识符。
从属名称是一个依赖于模板参数的标识符,如调用removeFromFront依赖于参数data,它有一个依赖于模板参数STACKTYPE的类型,模板实例化后才可以解析出它的名字。
相反,无参函数的标识符是非从属名称,如父类List中的isempty, 在定义模板的地方,这样的标识符就已经解析好了,如果模板没有实例化,那么非从属名称的函数的代码还不存在,这时编译器会产生编译错误,显式地加上this指针就会根据模板参数调用基类的成员函数。

使用List对象组合实现模板类Stack

在Stack模板类中创建一个List对象,通过该对象实现stack操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值