【问题标题】:How to determine size of a Linked List without using a while loop?如何在不使用 while 循环的情况下确定链表的大小?
【发布时间】:2016-03-15 07:39:36
【问题描述】:

我需要打印出链表中的节点数。我的老师说链表会跟踪它的数据并“知道”其中有多少个节点。所以,我不应该需要一个 while 循环来确定链表的大小。除了 while 循环之外,我很难找到打印大小的方法。

这是链表:

template <class T>
class LinkedList
{
private:
struct ListNode
{
  T data ;
  struct ListNode * next;
};

ListNode *head;

public:
LinkedList() { head = nullptr; }
 ~LinkedList();

// Linked list operations
void insertNode(T);
bool deleteNode(T);
void displayList() const;
};


/////////// Implementation portion of linked list with template  //////////////

// displayList: print all list data
template <class T>
void LinkedList<T>::displayList() const
{
ListNode * ptr = head;

while (ptr != nullptr)
{
    cout << ptr->data << endl;
    ptr = ptr->next;
}
}

// insertNode: add a node in list order
template <class T>
void LinkedList<T>::insertNode(T newValue)
{
ListNode *newNode;
ListNode *pCur;
ListNode *pPre = NULL;

newNode = new ListNode;
newNode->data = newValue;
newNode->next = nullptr;

if (head == nullptr)
{
  head = newNode;
}
else
{
    pCur = head;
    pPre = nullptr;
    while (pCur != nullptr && pCur->data < newValue)
    {
        pPre = pCur;
        pCur = pCur->next;
    }

    if (pPre == nullptr)
    {
        head = newNode;
        newNode->next = pCur;
    }
    else
    {
        pPre->next = newNode;
        newNode->next = pCur;
    }
}
}

// deleteNode: delete a node if found
template <class T>
bool LinkedList<T>::deleteNode(T toBeDeleted)
{
ListNode *pCur;
ListNode *pPre;

if (!head)
    return true;

pCur = head;
pPre = NULL;
while (pCur != NULL && pCur->data < toBeDeleted)
{
     pPre = pCur;
     pCur = pCur->next;
}

if (pCur != NULL && pCur->data == toBeDeleted)
{
    if (pPre)
        pPre->next = pCur->next;
    else
        head = pCur->next;
    delete pCur;
    return true;
}
return false;
}


// destructor, delete all nodes
template <class T>
LinkedList<T>::~LinkedList()
{
ListNode *ptr = head;
while (ptr != NULL)
{
    head = head->next;
    delete ptr;
    ptr = head;
}
}

【问题讨论】:

  • 这取决于你的链表是如何实现的。如果它跟踪节点的数量,那么您不需要循环。如果没有,那么您别无选择,只能遍历所有节点。由于您没有展示实现,我们无法提供答案。
  • 一种选择是以某种方式在每个节点上存储一个计数。然后你只需要访问尾部来找出有多少节点。但这会使添加和删除等操作复杂化。
  • 您的老师所说的仅适用于他想到的某些特定实现。有很多人不这样做。你需要问他他在谈论什么实现,或者如果他已经告诉过你,请查看你的讲义。
  • 如果列表“知道”它包含多少个节点,答案是询问它包含多少个节点。

标签: c++ while-loop linked-list size


【解决方案1】:

使用您定义的代码,列表的大小不会由列表直接存储。除此之外,链表的主要优点是每个节点都不知道链表的其余部分,存储大小会破坏这样做的目的。

但是,您可能误解了在不使用 while 循环方面对您的要求。每个节点都知道它的长度是 1+(它的尾部的长度),因此更适合获取链表长度的实现是递归,而不是迭代。

这是一个非常简单的 LinkedList 类的示例,它使用递归实现了简单的方法。如您所见,代码不使用迭代,只检查它自己的数据,然后为下一个节点调用相同的方法。尽管在大多数情况下,过程语言中的递归效率较低,但对于这样的结构,它无疑是优雅的。

#include <iostream>

template<class T>
class LinkedList
{
private:
    T data;
    LinkedList* next;
public:
    LinkedList()
        : LinkedList(T()) {
    }
    LinkedList(T value)
        : data(value), next(nullptr) {
    }
    ~LinkedList() {
        delete next;
    }

    void insertNode(T newValue) {
        if (!next) {
            next = new LinkedList(newValue);
            return;
        }

        next->insertNode(newValue);
    }

    void displayList() const {
        std::cout << data << std::endl;
        if (next) {
            next->displayList();
        }
    }

    T& at(int N) {
        if (N == 0) {
            return this->data;
        }
        return next->at(N-1);
    }

    int size() {
        if (!next) {
            return 1;
        }

        return 1+next->size();
    }
};


int main(int argc, char const *argv[])
{
    LinkedList<int>* test = new LinkedList<int>(0);

    for (int i = 1; i < 10; ++i) {
        test->insertNode(i);
    }

    std::cout << "List of length: " << test->size() << std::endl;
    test->displayList();

    return 0;
}

你会注意到我没有包含deleteNode,这是因为在列表只有一个节点的情况下,无法为上面过于简化的类编写它。实现这一点的一种可能方法是拥有一个包装类,就像您在原始代码中一样,它是一个指向链表开头的指针。见here

【讨论】:

  • 确实可以使用递归来求链表的长度,从而避免了while循环,但是递归实际上是一种循环,效率甚至比直接循环还要低。
  • @MichaelWalz,如答案中所述,是的,它通常在过程语言中效率较低。 OP 说:“我很难找出除了 while 循环以外的方法来打印大小。”所以我给出了唯一合理的答案。正如我也说过的,长度存储在节点类型中的链表违背了链表的目的,尽管在我链接到的包装类中可以很容易地完成。
  • 链接已断开
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
  • 1970-01-01
  • 1970-01-01
  • 2017-10-30
相关资源
最近更新 更多