双链表以及如何将迭代器移动到下一个节点

时间:2013-11-01 01:39:53

标签: c++ linked-list

我必须构建一个Deque列表并在Deque列表中,它有一个函数调用find,以查找列表中的值。但是,如果该节点不包含我正在搜索的值,那么尝试将iter移动到下一个节点时遇到问题。她是我发现功能的片段:

unique_ptr<DequeIterator<E>> find(E match)
{
    assert(!is_empty());
    bool is_found = true;

        // set the pointer point to the first node from the beginning        
    unique_ptr<DequeIterator<E>> iter(iter_begin());

    while(iter->node()->value() != match)
    {
                // here is I want to move the iter position
                // over to the next node
        iter->next();
                // print out the value at the node to re-check if
                // it matches
        cout << iter->node()->value() << endl;
    }

    if(is_found)
    {
        cout << "found" << iter->node()->value() << endl;

    }
    else
        cout << "no match" << endl;
    return iter;
}


unique_ptr<DequeIterator<E>> iter_begin()
{       
        // _head is set to nullptr inside the constructor
    return unique_ptr<DequeIterator<E>>(new DequeIterator<E>(_head));
}

DequeIterator class

template<class E>
class DequeIterator {
public:
  // You may need to modify this class. Feel free to modify the definitions of
  // these functions, or add new member functions.

  DequeIterator(DNode<E>* node) {
    _node = node;
  }

  bool at_end() {
    return _node == nullptr;
  }

  E value() {
    assert(!at_end());
    return _node->value();
  }

  void set_value(E x) {
    assert(!at_end());
    _node->set_value(x);
  }

  void next() {
    assert(!at_end());
    _node = _node->next();
  }

  DNode<E>* node() { return _node; }

private:
  DNode<E>* _node;
};

这是我的DNode类

template<class E>
class DNode {
public:
  DNode(DNode<E>* prev, E value, DNode<E>* next) {
    _value = value;
    _prev = prev;
    _next = next;
    dnode_census++;
  }

  ~DNode() {
    dnode_census--;
  }

  // The program crashes right here
  // after it goes into the E value()
  E value() { return _value; }
  void set_value(E value) { _value = value; }
  DNode<E>* prev() { return _prev; }
  void set_prev(DNode<E>* prev) { _prev = prev; }
  DNode<E>* next() { return _next; }
  void set_next(DNode<E>* next) { _next = next; }

private:
  E _value;
  DNode<E> *_prev;
  DNode<E> *_next;
};

Deque class

template<class E>
class Deque {
public:

Deque()
{
    _head = 0;
    _size = 0;
    _tail = 0;
}

  ~Deque() {
    clear();
  }

  // Make the deque empty. O(n) time.
  void clear() {
    while (!is_empty())
      erase_back();
  }

  // Return the current size of the deque. O(1) time.
  int size() {
    return _size;
  }

  // Return true when the deque is empty. O(1) time.
  bool is_empty() {
    return (size() == 0);
  }


unique_ptr<DequeIterator<E>> iter_begin()
{
    return unique_ptr<DequeIterator<E>>(new DequeIterator<E>(_head));
}

unique_ptr<DequeIterator<E>> iter_at(int index)
{
    assert((index >= 0) && (index <= size()));
    unique_ptr<DequeIterator<E>> iter(iter_begin());
    for(int j = 0; j < index; j++)
        iter->next();
    return iter;
}

E front()
{
    assert(!is_empty());
    return _head->value();
}


E back()
{
    assert(!is_empty());
    return _tail->value();
}


void insert_after(DequeIterator<E>& iter, E x)
{
    if(_size == 0)
    {
        insert_front(x);
    }
    else
    {
        assert(!iter.at_end());
        DNode<E>* temp = new DNode<E>(iter.node(), x, iter.node()->next());
        iter.node()->next()->set_next(temp);
        iter.node()->next()->set_prev(temp);
    }

    _size++;    
}

void insert_before(DequeIterator<E>& iter, E x)
{
    if(_size == 0)
    {
        insert_front(x);
    }
    else
    {
        assert(!is_empty());
        DNode<E>* temp2 = new DNode<E>(iter.node()->prev(), x, iter.node());
        (iter.node()->prev())->set_next(temp2);
        (iter.node()->prev())->set_prev(temp2);
    }
    _size++;    
}

void insert_front(E x)
{
    if(is_empty())
    {
        DNode<E>* temp = new DNode<E>(nullptr, x, nullptr);
        _head = temp;
        _tail = temp;
    }
    else
    {
        DNode<E>* temp = _head;
        DNode<E>* temp2 = new DNode<E>(nullptr, x, temp);
        _head = temp2;
    }
    _size++;
}


void insert_back(E x)
{
    if(is_empty())
    {
        insert_front(x);
    }
    else
    {
        assert(!is_empty());
        DNode<E>* temp = new DNode<E>(_tail, x, nullptr);
        _tail = temp;
        _size++;
        if(_size > 1)
            cout << _tail->prev()->value() << endl;
    }

}

void erase(DequeIterator<E>& iter)
{
    assert((!is_empty()) || !iter.at_end());

    DNode<E>* temp = iter.node();
    temp->next()->set_prev(temp->prev());
    temp->prev()->set_next(temp->next());

    delete iter.node()->next();
    _size--;
}

void erase_front()
{
    assert(!is_empty());
    DNode<E>* temp = _head;
    _head = temp->next();
    delete temp;
    _size--;

}


void erase_back()
{
    assert(!is_empty());
    DNode<E>* temp = _tail;
    _tail = temp->prev();
    delete temp;
    _size--;
}


unique_ptr<DequeIterator<E>> find(E match)
{
    assert(!is_empty());
    bool is_found = true;

    unique_ptr<DequeIterator<E>> iter(iter_begin());

    while(iter->value() != match)
    {
        iter->next();
        cout << iter->value() << endl;
    }

    if(is_found)
    {
        cout << "found" << iter->node()->value() << endl;

    }
    else
        cout << "no match" << endl;
    return iter;
}


 // Return the element value at position index, which must be
 // valid. O(n) time.
E get(int index) 
{
    assert((index >= 0) && (index < size()));

    unique_ptr<DequeIterator<E>> iter(iter_begin());

    for(int j = 0; j < index; j++)
        iter->next();
        return iter->node()->value();
}

void meld(Deque<E>& other)
{

}

private:
   DNode<E>* _head;
  DNode<E>* _tail;
  int _size;
};

的main.cpp

int main() {
  assert_no_leak(0);

  // Element objects to reuse. All upper case letters of the alphabet.
  //const int N = 5;
  const int N = 26;
  char letters[N];
  for (int i = 0; i < N; i++)
    letters[i] = 'A' + i;

  // Now there are a series of unit tests. Each test checks a few
  // related member functions. The tests use assert(...) to look for
  // bugs, so if one of these assertions fails, that indicates a bug
  // in your deque code.

  print_test_title("Deque constructor");
  unique_ptr<Deque<char>> q(new Deque<char>());
  assert_no_leak(0);

  print_test_title("Deque::size");
  assert(q->size() == 0);

  print_test_title("Deque::is_empty");
  assert(q->is_empty());

  print_test_title("Deque::insert_back");
  for (int i = 0; i < N; i++) {
    assert(q->size() == i);
    assert_no_leak(i);

    q->insert_back(letters[i]);

    assert(!q->is_empty());
    assert(q->size() == (i+1));
    assert_no_leak(i+1);
  }




  print_test_title("iteration");
  unique_ptr<DequeIterator<char>> iter(q->iter_begin());
  assert(!iter->at_end());
  assert_no_leak(N);
  for (int i = 0; !iter->at_end(); i++, iter->next()) {
    assert(i < N);
    assert(iter->value() == letters[i]);
    assert_no_leak(N);
  }
  assert_no_leak(N);

 /* for (int i = 0; i < N; i++)
      cout << q->get(i) << endl;*/


  print_test_title("Deque::find");

  iter = q->find('A');
  assert(!iter->at_end());
  assert(iter->value() == 'A');
  assert_no_leak(N);

  **// This is where I got the unhandled exception**
  iter =  q->find('T');
  assert(!iter->at_end());
  assert(iter->value() == 'T');
  assert_no_leak(N);

  iter = q->find('?');
  assert(iter->at_end());
  assert_no_leak(N);

  print_test_title("Deque::get");
  for (int index = 0; index < N; index++) {
    assert(q->get(index) == letters[index]);
    assert_no_leak(N);
  }

  print_test_title("Deque::front");
  assert(q->front() == 'C');
  assert_no_leak(N);

  print_test_title("Deque::back");
  assert(q->back() == 'Z');
  assert_no_leak(N);

  print_test_title("Deque::erase_front");
  for (int i = 0; i < N; i++) {
    assert(q->front() == letters[i]);
    assert(q->size() == (N-i));
    assert_no_leak(N-i);
    q->erase_front();
  }
  assert(q->is_empty());
  assert_no_leak(0);

  print_test_title("Deque::erase_back");
  for (int i = 0; i < N; i++)
    q->insert_back(letters[i]);
  for (int i = 0; i < N; i++) {
    assert(q->back() == letters[N-i-1]);
    assert(q->size() == (N-i));
    assert_no_leak(N-i);
    q->erase_back();
  }
  assert(q->is_empty());
  assert_no_leak(0);

  print_test_title("Deque::insert_front");
  for (int i = 0; i < N; i++) {
    q->insert_front(letters[i]);
    assert(q->front() == letters[i]);
    assert(q->size() == (i+1));
    assert_no_leak(i+1);
  }
  assert(q->size() == N);
  assert_no_leak(N);

  print_test_title("Deque::clear");
  q->clear();
  assert(q->is_empty());
  assert_no_leak(0);
  for (int size = 0; size <= N; size++) {
    assert(q->is_empty());
    assert_no_leak(0);

    for (int i = 0; i < size; i++)
      q->insert_back(letters[i]);

    assert(q->size() == size);
    assert_no_leak(size);

    q->clear();
    assert(q->is_empty());
    assert_no_leak(0);
  }

  print_test_title("insert_after, insert_before, erase");
  assert(q->is_empty());
  iter = q->iter_begin(); // iter is at end of empty queue
  q->insert_before(*iter, 'X');
  assert(queue_equals_string(*q, "X"));
  assert_no_leak(1);
  iter = q->iter_begin(); // iter is at start of queue with 1 element
  q->insert_after(*iter, 'O');
  assert(queue_equals_string(*q, "XO"));
  assert_no_leak(2);
  q->insert_after(*iter, 'Z');
  assert(queue_equals_string(*q, "XZO"));
  assert_no_leak(3);
  iter->next(); // iter is at second position (Z)
  q->insert_before(*iter, 'C');
  assert(queue_equals_string(*q, "XCZO"));
  assert_no_leak(4);
  q->insert_after(*iter, 'A');
  assert(queue_equals_string(*q, "XCZAO"));
  assert_no_leak(5);
  iter->next(); // iter is at fourth position (A)
  q->erase(*iter); // erase A
  assert(queue_equals_string(*q, "XCZO"));
  assert_no_leak(4);
  iter = q->iter_begin(); // X
  iter->next(); // C
  iter->next(); // Z
  q->erase(*iter); // erase Z
  assert(queue_equals_string(*q, "XCO"));
  assert_no_leak(3);
  q->erase(*q->iter_begin()); // erase X
  assert(queue_equals_string(*q, "CO"));
  assert_no_leak(2);
  iter = q->iter_begin(); // erase O
  iter->next();
  q->erase(*iter);
  assert(queue_equals_string(*q, "C"));
  assert_no_leak(1);
  q->erase(*q->iter_begin()); // erase C
  assert(queue_equals_string(*q, ""));
  assert_no_leak(0);

  print_test_title("Deque::splice");
  assert(q->is_empty());
  assert_no_leak(0);
  unique_ptr<Deque<char>> q2(new Deque<char>());
  assert_no_leak(0);
  for (int i = 0; i < 5; i++) {
    q->insert_back(letters[i]);
    q2->insert_back(letters[i]);
  }
  assert(q->size() == 5);
  assert(q2->size() == 5);
  assert_no_leak(10);
  q->meld(*q2);
  assert(q->size() == 10);
  assert(q2->is_empty());
  assert_no_leak(10);
  assert(queue_equals_string(*q, "ABCDEABCDE"));

  if (DO_PERFORMANCE_TEST) {
    print_test_title("Performance");
    q->clear();
    time_t start = time(nullptr);
    for (int i = 0; i < BIG_N; i++) {
      q->insert_front('A');
      if ((i % 1000) == 0)
        cout << '.';
    }
    time_t stop = time(nullptr);
    assert(q->size() == BIG_N);
    cout << endl
         << "  Elapsed time to insert_front " << BIG_N << " times: " 
         << (stop - start) << " seconds" << endl;
  }

  return 0;
}

1 个答案:

答案 0 :(得分:3)

你并没有真正对迭代器做任何事情。重点是你想要改变它以指向列表中的下一个项目。

通常使用迭代器,您将实现operator++。它可能看起来像这样:

template <class E>
DequeIterator<E> & DequeIterator::operator++()
{
    _node = _node->next;
    return *this;
}

目前尚不清楚为什么要分配迭代器并使用unique_ptr。通常你按值返回迭代器,它们的内部结构非常简单(指针或两个)。无需在堆上分配它们。


看到你的迭代器代码后,你似乎只是使用了错误的next()。您在当前节点上调用它,而不是迭代器:

iter->node()->next();   // incorrect
iter->next();           // correct

正如 WhozCraig 在评论中所建议的那样:

  

此迭代器与后增量匹配之间的差异   可以保证使用其按值临时复制返回的实现   随便的读者。

我提供的++操作是前缀运算符,这意味着您需要执行++*iter。如果你想(*iter)++,你需要一个后缀运算符:

template <class E> DequeIterator<E> DequeIterator::operator++(int) {
    DequeIterator<E> temp(*this);
    _node = _node->next;
    return temp;
}

由于您的列表是双链接的,因此您可能希望提供相应的--前缀和后缀运算符。