Достичь статический один список

 

Сценарии использования:
Частые делеции элементы данных
максимальное количество элементов данных в фиксированном

 

Единый список дефектов
- Триггеры
  длительное использование одного списка объектов , часто добавлять и удалять элементы данных
- вероятный результат
  кучи пространство большое количество фрагментации памяти, заставить систему работать медленно

Объяснение:

Если при добавлении одного элемента данных в список и они будут создавать узел соединения для кучного пространства, чтобы сделать это без каких-либо проблем с процедурной точки зрения, но в течение длительного времени Частое создание и удаление узел соединения в некоторых системах точка, можно производить большое количество кучной фрагментации памяти. При фрагментации памяти, прямым результатом является то, что система работает медленно. Это недостаток односвязный список реализации.

Новые линейные формы
идеи дизайна:
увеличить пространство , отведенное внутри единого список всех объектов Node в этом пространстве в создании динамического и разрушении динамической
формы заказа единого списка + = статический единый список

Иерархия наследования статического один список

 

Статическое добавление одной цепи к различным способам памяти, одной цепи и других операции точно так же до реализации.

Думая статический единый связанный список реализуется
через шаблон определяет один статический член ObjectList (StaticLinkList) ,
определенный в классе в виде фиксированного размера пространства (неподписанный символ [])
переписывания создавать и уничтожать функции, изменяя распределение способа памяти и реституцию
вес в классе Node оператор загрузки новый, создавать объекты в указанной памяти

Статический один список для достижения:

Посмотрите, как узел LinkList.h в этом типе определен.

структура Node: общественный объект

{

  T value; //既然是泛指类型的value,那么这个value就有可能是一个对象(用户自定义类类型的对象),必然牵涉到构造函数调用的问题了。value构造函数的调用,必然牵涉到Node构造函数的调用了(value是Node的一个成员变量)

  Node* next;

};

在StaticLinkList.h中,再看一下create函数的定义,

Node* create()

    {

        Node* ret = NULL;

        for(int i=0; i<N; i++)  //首先遍历空间哪些是可用的,就是通过这个标记数组来判断。

        {

            if(!m_used[i])

            {

                ret = reinterpret_cast<SNode*>(m_space) + i; //首先做强制类型转换,再做指针运算。内存分配好了之后,还需要在指定的内存上调用构造函数,因此需要重载new操作符。

                m_used[i] = 1;

                break;

            }

        }

        return ret;

    }

这里面不涉及Node构造函数的定义。仅仅是单纯的分配内存,并没有涉及到构造函数的调用。

分配好内存之后,我们还需要在指定的内存上调用构造函数。此时就需要重载new操作符了。

struct SNode : public Node

{

  //loc保存了一个内存地址,该内存地址就是调用构造函数的内存地址

  void* operator new(unsigned int size, void* loc)

  {

    return loc;

  }

};

Node* create()

    {

        SNode* ret = NULL;

        for(int i=0; i<N; i++)  //首先遍历空间哪些是可用的,就是通过这个标记数组来判断。

        {

            if(!m_used[i])

            {

                ret = reinterpret_cast<SNode*>(m_space) + i; //首先做强制类型转换,再做指针运算。内存分配好了之后,还需要在指定的内存上调用构造函数,因此需要重载new操作符。

                ret = new(ret) SNode();

                m_used[i] = 1;

                break;

            }

        }

        return ret;

    }

void destroy(Node* pn)

{

  SNode* space = reinterpret_cast<SNode*>(m_space);

  SNode* psn = dynamic_cast<SNode*>(pn);//从父类指针,转换为子类指针,直接调用dynameic_cast

 

  for(int i=0; i<N; i++)

  {

    if(psn == (space + i))

    {

      m_used[i] = 0;

      psn->~SNode();

    }

  }

}

具体代码如下:

#ifndef STATICLINKLIST_H
#define STATICLINKLIST_H

#include "linklist.h"

namespace DTLib
{

template <typename T,int N> //N用来定义预留大小空间使用的
class StaticLinkList : public LinkList<T>
{
protected:
    typedef typename LinkList<T>::Node Node; //为什么需要加上typename,因为LinkList<T>::Node这种写法,根本就无法确定Node是一种类型还是静态成员变量。

    struct SNode : public Node
    {
        //loc保存了一个内存地址,该内存地址就是调用构造函数的内存地址
        void* operator new(unsigned int size, void* loc)
        {
            (void)size;
            return loc;
        }
    };

    unsigned char m_space[sizeof(SNode) * N]; //定义预留的空间
      int m_used[N]; //标记数组

    Node* create()
    {
        SNode* ret = NULL;

        for(int i=0; i<N; i++)  //首先遍历空间哪些是可用的,就是通过这个标记数组来判断。
        {
            if(!m_used[i])
            {
                ret = reinterpret_cast<SNode*>(m_space) + i; //首先做强制类型转换,再做指针运算。内存分配好了之后,还需要在指定的内存上调用构造函数,因此需要重载new操作符。
                       ret = new(ret) SNode();
                m_used[i] = 1;
                break;
            }
        }
        return ret;
    }

    void destroy(Node* pn)
    {
        SNode* space = reinterpret_cast<SNode*>(m_space);
        SNode* psn = dynamic_cast<SNode*>(pn);//从父类指针,转换为子类指针,直接调用dynameic_cast

          for(int i=0; i<N; i++)
        {
            if(psn == (space + i))
            {
                m_used[i] = 0;
                psn->~SNode();
            }
        }
    }

public:
    StaticLinkList()
    {
        for(int i=0; i<N; i++)
        {
            m_used[i] = 0;
        }
    }

    int capacity()
    {
        return N; //表示静态单链表最多可以容纳多少个数据元素
    }
};

}

#endif // STATICLINKLIST_H

LinkList中封装create和destroy函数的意义:

为静态单链表(StackLinkList)的实现做准备。StaticLinkList与LinkList的不同仅在于链表结点内存分配上的不同。因此将仅有的不同封装于父类和子类的虚函数中

小结:

顺序表与单链表相结合后衍生出静态单链表

静态单链表是LinkList的子类,拥有单链表的所有操作

静态单链表在预留的空间中创建结点对象

静态单链表适合于频繁增删数据元素的场合(最大元素个数固定)

 

рекомендация

отwww.cnblogs.com/-glb/p/12147366.html
рекомендация