函数指针返回

时间:2014-02-15 16:16:32

标签: c++ pointers iterator

我在这段代码中有3个问题:

#include <cassert>
#include <utility>

template <typename T>
class BST
{
private:
    struct Node
    {
        T data;
        Node * left, * right;

        Node () : data (), left (nullptr), right (nullptr) {}
        Node (T const & v, Node * left_, Node * right_) : data (v), left (left_), right (right_) {}
    };

public:
    class Iterator
    {
        friend class BST;

    private:
        Iterator ();
        explicit Iterator (Node * node);

    public:
    };

public:
    BST ()
        : m_root (nullptr)
    {}

    ~BST ()
    {
        clear ();
    }

    void clear ()
    {
        clear (m_root);
    }

    Iterator insert (T const & v)
    {
        Node * p = new Node (v, nullptr, nullptr);

        if (nullptr == m_root)
            m_root = p;
        else
            insert (m_root, p);

        return Iterator(p);
    }

    Iterator find (T const & v) const
    {
        Node * p = find (m_root, v);
        if (nullptr != p)
            return Iterator(p);
        else
            Iterator();
    }

    int size () const
    {
        return size(m_root);
    }

    int height () const
    {
        return height(m_root);
    }

    // For Sunday, 1392/11/27 23:59
    int depth (Iterator it) const;  // <---
    bool erase (T const & v);       // <---
    bool erase (Iterator it);       // <---
    void printInfix () const;       // <---
    void printPrefix () const;      // <---

private:
    void clear (Node * root)
    {
        if (nullptr == root)
            return;
        clear (root->left);
        clear (root->right);
        delete root;
    }

    void insert (Node * root, Node * node)
    {
        assert (root != nullptr);
        assert (node != nullptr);

        if (node->data < root->data)
            if (nullptr != root->left)
                insert (root->left, node);
            else
                root->left = node;
        else
            if (nullptr != root->right)
                insert (root->right, node);
            else
                root->right = node;
    }

    Node * find (Node * root, T const & v) const
    {
        if (nullptr == root)
            return nullptr;

        if (v < root->data)
            return find(root->left, v);
        else if (root->data < v)
            return find(root->right, v);
        else    // Eureka!
            return root;
    }

    int size (Node * root) const
    {
        if (nullptr == root) return 0;
        return 1 + size(root->left) + size(root->right);
    }

    int height (Node * root) const
    {
        if (nullptr == root) return 0;
        return 1 + std::max(height(root->left), height(root->right));
    }

private:
    Node * m_root;
};

Iterator实际上做了什么,为什么我们使用它?

什么是明确的,它做了什么?

和重要的一个:为什么我们从一个函数返回例如“Node *”?我们如何使用它?以及如何在此代码中工作?

非常感谢......!

1 个答案:

答案 0 :(得分:1)

首先,我将回答你的上一个问题:

  

为什么我们从函数返回例如“Node *”?我们如何使用它?   以及如何在此代码中工作?

Node*表示“指向节点的指针”。我们返回Node *,因为Node本身存储在BST的“内部”。当你说'找到一个值为5的节点'时,你不想创建一个新节点,对吗?您希望BST在树中找到具有此类值的现有Node,然后返回指针,以便您可以直接对其进行操作。如果返回类型声明为Node,则每次都会创建新节点,因此对返回的对象进行操作不会更改存储在树中的原始节点的状态。

将函数声明为返回Node *也有一个原因 - 在这种情况下,函数可以返回NULL(表示'零','无','指向什么都没有'),并通过此信号表明所需的值不是出现在树上。使用Node,函数必须始终返回一个对象,您需要有一种方法来检查它是否是一个有效的对象。

返回的指针可以这样使用:

Node* node = bst.find(5);
std::cout<<"Node value: "<<*node;
*node = 10;
std::cout<<"Node value after change: "<<*node;

如果你不熟悉指针,你应该检查一下: http://alumni.cs.ucr.edu/~pdiloren/C++_Pointers/ http://www.howtoforge.com/pointers_c_plusplus

现在,关于迭代器:

就C ++而言,

Iterator可以简单地描述为“用于迭代元素集合的对象”。最简单的集合是以这种方式定义的数组:

int table[100]

这是100个整数的集合。您可以使用如下指针迭代它们:

int* table_iter = table; //or: int* table_iter = &table[0]
int index = 0;
while(index < 100)
{
  *table_iter = 10; //Set value of number currently pointed by iterator
  ++table_iter; //Move iterator to next element
}

当然我命名了我的指针table_iter,但这是普通的标准指针。但是这种迭代也可以在没有指针的情况下完成。例如:

for(int index = 0; index < 100; ++index)
{
  table[index] = 10;
}

我们更喜欢第一种解决方案,因为元素访问总是涉及偏移计算。这意味着,为了了解table[index]的位置,程序必须使用table的地址,然后将table类型的值加上index。当然,有一些优化可以在如上所述的简单for中执行,但我在这里谈论非常一般的情况。在迭代器的情况下,我们所做的只是简单的“递增1”,如果是指针,则意味着将指针移动指针类型的一个元素。

现在,还有一个原因,我们更喜欢第一种符号 - 与迭代器背后的原因相同 - 因为它是通用符号。这是什么意思?这意味着在第一个样本中我们会这样说:

  • 指针设置为第一个元素。
  • 直到当前位置仍有元素:
  • 使用此元素执行某些操作
  • 指针设置为集合中的下一个元素。

我标记了指针,因为这正是迭代器所在 - 指向集合中某个元素的指针。

现在,让我们仔细看看for()版本。它说:

  • n = 0 .... 99
  • 使用table[n]
  • 上的元素执行某些操作

你看到了区别吗?迭代器本身不会假设它可以迭代的集合。这比我们通常称之为for each的冷酷。这就是他们被引入的原因 - 他们隐藏了迭代内部的细节。想一想 - 你会如何使用指针来完成二叉树?哈希地图?八叉树?使用迭代器时,代码看起来几乎完全相同:

Collection<int> ints;
ints.add(5); //add() is a memeber function that adds new element to collection.
ints.add(6);
//... etc
Collection::Iterator iter = ints.begin(); //Set `iter` to the beginning of out collection.
while(iter != ints.end()) //While there are still elements...
{
  *iter = *iter * 2; //Multiply every int by 2 and save it.
}

重要的是,在上面的代码中Collection可能是任何东西 - List,Vector,BST,HashMap,Octree ......迭代器隐藏了我们的迭代细节。

同样很明显,不同集合的迭代器以不同的方式实现 - 它们在内部存储正常工作所需的信息(指针,偏移,位置),但从用户的角度来看,它们是简单的“指针”,可以向前/向后移动以通过元素。

另外,你应该理解,Iterator通常不是一个类型 - 它是一个概念,抽象层,它隐藏了特定任务的一些实现细节(在这种情况下是迭代)。 std::vector<int>::iterator是一种具体类型,std::multimap<int, std::string>::iterator也是如此。但是,“Iterator”存在于许多现代编程语言中,当它们可以以不同的名称存在时。