实现list的简单模型

list 是一个带头的双向循环链表

结点构造

参数用匿名对象,方便直接构造结点。

  template<class T>
  struct list_node
    {
      list_node<T>* _next;
      list_node<T>* _prev;
      T _data;

      list_node(const T& val = T())
        :_next(nullptr)
         ,_prev(nullptr)
         ,_data(val)
      {}
    };

迭代器的构造

迭代器本质上是结点的指针,但是 list 结点不是连续的,因此原生指针的特性必须由我们自己实现

迭代器是指针,结点不属于自己,不能释放结点,因此没有析构函数 

参照源码逻辑:这里是写一个迭代器的模板,下面传参时可以根据类型的不同,来确定是实例化普通的迭代器还是 const 类型的迭代器。

用 self 代替模板,方便模板参数类型的替换

Ref 和 Ptr

注意 * 和 -> 这两个符号的重载:it 是一个 int* 

*it = 10;

* 是对指针解引用,直接可以改变数据,因此返回的是数据的引用;

it->data;

-> 直接对指针指向的内容进行访问,返回的应该是存储数据的地址

而引用 Ref 和 Ptr 的目的就是为了区分迭代器类型

  template<class T, class Ref, class Ptr>
  struct _list_iterator
  {
    typedef list_node<T> Node;
    typedef _list_iterator<T, Ref , Ptr> self;
    Node* _node;

    //没有析构函数--结点不属于迭代器,不能被迭代器释放
    //拷贝构造和赋值重载--默认生成的浅拷贝就可以
    _list_iterator(Node* node)
      :_node(node)
    {}

    //T& 或者 const T&
    Ref operator*()
    {
      return _node->_data;
    }

    //T* 或者 const T*
    Ptr operator->()
    {
      return &(operator*());
    }

    self& operator++()   //前置++
    {
       _node = _node->_next;
       return *this;
    }

    self& operator++(int)   //后置++
    {
       self tmp(*this);
       _node = _node->_next;
       return tmp;
    }

    self& operator--()   //前置--
    {
       _node = _node->_prev;
       return *this;
    }

    self& operator--(int)   //后置--
    {
       self tmp(*this);
       _node = _node->_prevt;
       return tmp;
    }

    bool operator!=(const self& it)
    {
      return _node != it._node;
    }

    bool operator==(const self& it)
    {
      return _node == it._node;
    }

  };

list 的对迭代器的实例化

在 list 中,通过控制模板参数的不同,来完成传参时,对不同迭代器的实例化。

  template<class T>
  class list 
    {
      typedef list_node<T> Node;
    public:
      typedef  _list_iterator<T,T&,T*> iterator;
      typedef  _list_iterator<T,const T&,const T*> const_iterator;
     
      const_iterator begin() const 
      {
        return const_iterator(_head->_next);
      }

      const_iterator end() const 
      {
        return const_iterator(_head);
      }
      iterator begin()
      {
        return iterator(_head->_next);
      }

      iterator end()
      {
        return iterator(_head);
      }

      list()
      {
        _head = new Node();
        _head->_next = _head;
        _head->_prev = _head;
      }

    private:
      Node* _head;
    };

打印函数传参

  void print_list(const list<int>& lt)
  {
    list<int>::const_iterator it = lt.begin();
    while(it != lt.end())
    {
      cout << *it << " ";
      ++it;
    }

    cout << endl; 
  }

在构造 list 时,指定迭代器的三个模板参数类型,将 const 和普通迭代器区分开来;

例如当我们想打印出一个 list 中的数据时,给打印函数传过去的是 const list<int>& lt

那么此时用到 const_iterator 匹配到的就是如下模板:

typedef  _list_iterator<T,const T&,const T*> const_iterator;

这样构建出的迭代器就不能修改数据了。 

list 的构造函数

list 带头双向循环链表,我们在构造时主要是开辟头结点,令前后指针指向自身

empty_init 是初始化一个 list 的头结点

支持迭代器区间构造

现代写法完成拷贝构造

      list()
      {
        _head = new Node();
        _head->_next = _head;
        _head->_prev = _head;
      }

      //拷贝构造传统写法
      //list(const list<T>& lt)
      //{
      //   _head = new Node();
      //  _head->_next = _head;
      //  _head->_prev = _head;
      //  for(auto e: lt)
      //  {
      //    push_back(e);
      //  }
      //}
      //
      
      void empty_init()
      {
        _head = new Node();
          _head->_next = _head;
          _head->_prev = _head;
         
      }

      template<class InputIterator>
        list(InputIterator first,InputIterator last)
        {
          empty_init();   
          while(first != last)
          {
            push_back(*first);
            ++first;
          }
        }

      void swap(list<T>& lt)
      {
        std::swap(_head,lt._head);
      }
      
      //现代写法
      list(const list<T>& lt)
      {
        empty_init();
        list<T> tmp(lt.begin(),lt.end());
        swap(tmp);
      }

      list<T>& operator=(list<T> lt)
      {
        swap(lt);
        return *this;
      }
     

插入删除

尾插尾删和头插头删可以复用插入和删除

插入时总是插入在指定位置的前面,不会造成迭代器失效的问题

删除会造成迭代器失效,野指针问题,返回的是删除位置的下一个位置

      void push_back(const T& x)
      {
        insert(end(),x);
      }

      void push_front(const T& x)
      {
        insert(begin(),x);
      }

      void pop_back()
      {
        erase(--end());
      }

      void pop_front()
      {
        erase(begin());
      }

      //插入在pos位置之前
      void insert(iterator pos,const T& x)
      {
        Node* newnode = new Node(x);
        Node* cur = pos._node;
        Node* prev = cur->_prev;
        newnode->_next =  cur;
        cur->_prev = newnode;
        prev->_next = newnode;
        newnode->_prev = prev;
      }

      iterator erase(iterator pos)
      {
        assert(pos != end());
        Node* cur = pos._node;
        Node* prev = cur->_prev;
        Node* next = cur->_next;
        prev->_next = next;
        next->_prev = prev;
        delete cur;
        return next;
      }

析构函数

调用析构函数前,先要将数据删除,再释放头结点

clear 可以删除全部结点,刚好保留头结点

      ~list()
      {
        clear();
        delete _head;
        _head = nullptr;
      }
 
      void clear()
      {
        iterator it = begin();
        while(it != end())
        {
          it = erase(it);
        }
      }

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
Java中没有 DataTable 类,但是可以使用 Java 中的类来实现类似 DataTable 的数据模型。其中最常用的类是 ArrayList 和 HashMap。 以下是一个简单的示例: ```java import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class DataTable { private List<Map<String, Object>> rows; private String[] columns; public DataTable(String[] columns) { this.columns = columns; this.rows = new ArrayList<>(); } public void addRow(Object[] rowData) { Map<String, Object> row = new HashMap<>(); for (int i = 0; i < rowData.length; i++) { String columnName = this.columns[i]; Object columnValue = rowData[i]; row.put(columnName, columnValue); } this.rows.add(row); } public List<Map<String, Object>> getRows() { return this.rows; } public String[] getColumns() { return this.columns; } public int getRowCount() { return this.rows.size(); } public Object getValue(int rowIndex, String columnName) { Map<String, Object> row = this.rows.get(rowIndex); return row.get(columnName); } public void setValue(int rowIndex, String columnName, Object value) { Map<String, Object> row = this.rows.get(rowIndex); row.put(columnName, value); } } ``` 这个类使用 List<Map<String, Object>> 存储数据行,其中每个 Map 表示一行数据,其中 key 为列名,value 为列值。addRow() 方法通过将 rowData 转换为 Map 来添加新的行,getValue() 和 setValue() 方法利用 Map 的 get() 和 put() 方法获取和设置列值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今年依旧去年春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值