【问题标题】:Back Traversal issue in linked list返回链表中的遍历问题
【发布时间】:2021-01-05 07:32:55
【问题描述】:

以下是C++编写的带有Node类和main函数的链表。 List 正在使用“next()”函数向前遍历,但在使用“back()”向后遍历时会产生执行时间错误。

#include <iostream>
using namespace std;

class Node {
    public:
        int object;
        Node *nextNode;
        Node *prevNode;
        
    public:
        
        int get(){
            return object;
        }
        
        void set(int object){
            this->object = object;
        }
        
        Node* getNext(){
            return nextNode;
        }
        
        void setNext(Node *nextNode){
            this->nextNode = nextNode;
        }
        
        Node* getPrev(){
            return prevNode;
        }
        
        void setPrev(Node *prevNode){
            this->prevNode = prevNode;
        }
        
    
};


class List {
    public:
        Node* headNode;
        Node* currentNode;
        int size;
    
    public:
        
        List(){
            headNode = new Node();
            headNode->setNext(NULL);
            headNode->setPrev(NULL);
            currentNode = NULL;
            int size = 0;   
        }
        
        void add(int addObject){
            Node* newNode = new Node();
            newNode->set(addObject);
            
            if(currentNode != NULL){
                newNode->setNext(currentNode->getNext());
                newNode->setPrev(currentNode);
                currentNode->setNext(newNode);
                currentNode = newNode;
                            
            }
            else {
                newNode->setNext(NULL);
                newNode->setPrev(headNode);
                headNode->setNext(newNode);
                currentNode = newNode;
            }
            
            size++;
    
        }
        
        int get(){
            if(currentNode != NULL) {
                return currentNode->get();
            }
        } 
        
        bool next(){
            if(currentNode == NULL) return false;
            
            currentNode = currentNode->getNext();
            
            if(currentNode == NULL) return false;
            else                    return true;
        
        }
        
        bool back(){
            if(currentNode == NULL) return false;
            currentNode = currentNode->getPrev();
            
            if(currentNode == NULL) return false;
            else return true;
        }
        
        void start(){
            currentNode = headNode;
        }
        
        void remove() {
            if (currentNode != NULL && currentNode != headNode){
                delete currentNode;
                size--;
            }
        }
        
        int length() {
            return size;
        }
        
};


int main(){
    
    List list;
    
    list.add(5);
    list.add(13); 
    list.add(4);
    list.add(8);
    list.add(48);
    list.add(12); 
    
    list.start(); 
    
    while(list.next()){
        cout<<endl<<"Element: " << list.get() << endl;
    }
     
    cout<<endl<<"BACK"<<endl;

    while(list.back()){
        cout<<endl<<"Element: " << list.get() << endl;
    } 
}

Back() 函数应该以相反的方向(从头到尾)遍历列表。反向方式。这段代码有时会挂起 CPU,有时只运行 next() 函数,而对于 back() 函数,它保持沉默,不做任何事情。

【问题讨论】:

  • 这可能与您的 get 函数在发生 Null 时不会返回任何内容的事实有关
  • 您是否尝试调试代码并检查指针是否指向预期位置?
  • 我尝试调试但可以找到它
  • add 中插入新节点时,会更新current-&gt;next 指针。但是你没有更新current-&gt;next-&gt;prev,所以反向结构永远不会正确形成。
  • @Asad Razaq 把那个糟糕的代码扔进垃圾桶然后重新重写列表实现。:)

标签: c++ algorithm data-structures linked-list


【解决方案1】:

首先,让我们修复代码:

 bool next(){
        if(currentNode == nullptr)  return false; 
        // if next is null we are at the end, don't go futher
        if (  currentNode->getNext() == nullptr ) return false;
        currentNode = currentNode->getNext();
        return true;
    }
    
    bool back(){
        if(currentNode == nullptr) return false;
        
        // if prev is head, we are at the start, stop here 
        if ( currentNode->getPrev() == headNode) return false;
        currentNode = currentNode->getPrev();
       
        return true;
    }

逻辑:

// we are at the last element, so we have to print BEFORE going back
do{
    cout<<endl<<"Element: " << list.get() << endl;
} while (list.back());

Demo live


警告:

警告:未使用的变量“大小”

在这种情况下,出现这个警告是可以的,如果你想摆脱它,可以使用 length()的方法。

在成员函数'int List::get()'中: 警告:控制到达非空函数的结尾 [-Wreturn-type]

在您的 get 方法中,if(currentNode == nullptr ) 您什么也不返回,这将导致错误。解决此问题的一种方法是 throwexception

int get(){
    if(currentNode == nullptr ) {
       throw std::logic_error("CurrentNode is null");
    }
    return currentNode->get();
} 

我个人认为最好的解决方案是:编码List的所有成员函数,使currentNode不能为空。


内存管理

您使用new 创建您的节点,但您从不使用delete,所以您有一个memory leak。查看 valgrind(site webthis nice post),它非常有帮助。

valgrind ./leaky --leak-check=full
....
==3225== HEAP SUMMARY:
==3225==     in use at exit: 168 bytes in 7 blocks
==3225==   total heap usage: 9 allocs, 2 frees, 73,896 bytes allocated
==3225== 
==3225== LEAK SUMMARY:
==3225==    definitely lost: 24 bytes in 1 blocks 
==3225==    indirectly lost: 144 bytes in 6 blocks
==3225==      possibly lost: 0 bytes in 0 blocks
==3225==    still reachable: 0 bytes in 0 blocks
==3225==         suppressed: 0 bytes in 0 blocks

所以是的,valgrind 发现了一个漏洞。

您需要添加destructor

~List(){
       // first be sure that we are at one end
       while (next()) {}
        
       while (back())
       {
           std::cout << "delete the node we just left : " << currentNode->getNext()->get() << std::endl;
           delete currentNode->getNext();
       }
       // don't forget this one (without valgrind I will have miss it!)
       delete currentNode;

       std::cout << "finaly we clear the head" << std::endl;
       delete headNode;
}

但是现在如果我们写:

List list2 = list;

我们得到了:

double free or corruption (fasttop)

因为我们有 2 个对象试图删除相同的内存。

我们可以禁止复制:

 List(const List&) = delete;
 List& operator=(const List&) = delete;

通常大多数内存管理是通过smart pointer完成的。


可见性:

使用private 作为您的属性:

private :
    int object;
    Node *nextNode;
    Node *prevNode;

private:
    Node* headNode;
    Node* currentNode;
    size_t size = 0;
 

最终版本:Demo

检查 valgrind:

==3532== HEAP SUMMARY:
==3532==     in use at exit: 0 bytes in 0 blocks
==3532==   total heap usage: 9 allocs, 9 frees, 73,896 bytes allocated
==3532== 
==3532== All heap blocks were freed -- no leaks are possible

没有泄漏,一切都很好;)

希望对你有帮助!

【讨论】:

    猜你喜欢
    • 2013-07-28
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-26
    • 1970-01-01
    相关资源
    最近更新 更多