簡體   English   中英

用C ++反轉單鏈表

[英]Reversing a singly-linked list in C++

我試圖以遞歸方式反轉單鏈表的實現時遇到問題。

我已經閱讀了關於這個過程的其他類似問題,但是,在我嘗試在我自己的程序中實現這個過程時,我做得很簡短。

這是我在下面的嘗試(與之后的代碼中顯示的略有不同):

注意:我的列表使用root指針,該指針不包含重要數據,僅用作引用列表中數據的地址。

void IntList::reverse(Node* t_node) {
    if(t_node == NULL) {
        reverse(root);
    } else

    if(t_node->next == NULL) {
        cout << "In (swapping): " << t_node->value << endl;
        root->next = t_node;
    } else {
        cout << "In: " << t_node->value << endl;
        Node* tmp = t_node->next;
        reverse(t_node->next);
        tmp->next = t_node;
    }
    return NULL;
}

我在某個地方丟失了引用,並在嘗試顯示列表時無休止地打印。 我真的不知道我犯的錯誤是什么,但懷疑它可能與我如何處理我的root

這是完整程序的全部(除了reverse()方法之外的所有功能)。

#ifndef INTLIST_H
#define INTLIST_H
#include<iostream>
using namespace std;
class IntList {
private:
   struct Node {
      int value;
      Node* next;
   };
   int size;
   Node* root;
   void destroy();
public:
   IntList() { root = new Node; root->next = 0; root-> value = 0; size = 0;}
   IntList(const IntList& list) { this->root = list.root; this->size = list.size; }
   ~IntList() {}
   void appendNode(int val);
   void insertNode(int pos, int val);
   void deleteNode(int pos);
   int searchNode(int val);
   int getSize() const;
   void print() const;
   Node* reverse(Node* t_node);
   int &operator[](int element) const;
   void pop_back();
   void pop_front();
   void push_back(int val);
   void push_front(int val);
};
void IntList::appendNode(int val) {
    push_back(val);
}
void IntList::insertNode(int pos, int val) {
    Node* tmp;
    Node* current = root;
    for(int i = 0; i < pos && current->next != NULL; i++) {
        current = current->next;
    }
    tmp = new Node;
    tmp->value = val;
    tmp->next = current->next;
    current->next = tmp;
    size++;
}
void IntList::deleteNode(int pos) {
    Node* tmp;
    Node* current = root;
    if(pos <= size-1) {
        for(int i = 0; i < pos; i++) {
            current = current->next;
        }
        tmp = current->next;
        current->next = tmp->next;
        delete tmp;
        size--;
    } else {
        cout << "ERROR: Out of range." << endl;
    }
}
int IntList::searchNode(int val) {
    int position = 0;
    Node* current = root->next;
    if(size != 0) {
        for(position = 0; position < size && current->value != val; position++) {
            current = current->next;
        }
    } else {
        cout << "ERROR: List is empty." << endl;
        position = -1;
    }
    return position;
}
int IntList::getSize() const {
    return size;
}
void IntList::print() const {
    Node* current = root->next;
    cout << "List: ";
    while(current != NULL) {
        cout << current->value << " ";
        current = current->next;
    }
    if(getSize() == 0) {
        cout << "Empty.";
    }
    cout << endl;
}
IntList::Node* IntList::reverse(Node* t_node) {
#define REVERSE
#ifndef REVERSE
    if(t_node == NULL) {
        reverse(root);
    } else

    if(t_node->next == NULL) {
        cout << "In (swapping): " << t_node->value << endl;
        root->next = t_node;
    } else {
        cout << "In: " << t_node->value << endl;
        Node* tmp = t_node->next;
        reverse(t_node->next);
        tmp->next = t_node;
    }
#endif //reverses list, but causes infinite loop in display
    return NULL;
}
int &IntList::operator[](int pos) const {
    Node* current = root->next;
    if(pos <= size-1) {
        for(int i = 0; i < pos; i++) {
            current = current->next;
        }
    } else {
        cout << "ERROR: Out of bounds.";
        current = NULL;
    }
    return current->value;
}
void IntList::pop_back() {
    deleteNode(size-1);
}
void IntList::pop_front() {
    deleteNode(0);
}
void IntList::push_back(int val) {
    insertNode(size, val);
}
void IntList::push_front(int val) {
    insertNode(0, val);
}
#endif

#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include<iostream>
using namespace std;
template<typename T>
class LinkedList {
private:
   struct Node {
      T value;
      Node* next;
   };
   int size;
   Node* root;
   void destroy();
public:
   LinkedList() { root = new Node; root->next = 0; root-> value = 0; size = 0;}
   LinkedList(const LinkedList &) {}
   ~LinkedList() {}
   void appendNode(T val);
   void insertNode(int pos, T val);
   void deleteNode(int pos);
   int searchNode(T val);
   int getSize() const;
   void print() const;
   void reverse(Node* t_node);
   int &operator[](int element) const;
   void pop_back();
   void pop_front();
   void push_back(T val);
   void push_front(T val);
};
template <typename T>
void LinkedList<T>::appendNode(T val) {
    push_back(val);
}
template <typename T>
void LinkedList<T>::insertNode(int pos, T val) {
    Node* tmp;
    Node* current = root;
    for(int i = 0; i < pos && current->next != NULL; i++) {
        current = current->next;
    }
    tmp = new Node;
    tmp->value = val;
    tmp->next = current->next;
    current->next = tmp;
    size++;
}
template <typename T>
void LinkedList<T>::deleteNode(int pos) {
    Node* tmp;
    Node* current = root;
    if(pos <= size-1) {
        for(int i = 0; i < pos; i++) {
            current = current->next;
        }
        tmp = current->next;
        current->next = tmp->next;
        delete tmp;
        size--;
    } else {
        cout << "ERROR: Out of range." << endl;
    }
}
template <typename T>
int LinkedList<T>::searchNode(T val) {
    int position = 0;
    Node* current = root->next;
    if(size != 0) {
        for(position = 0; position < size && current->value != val; position++) {
            current = current->next;
        }
    } else {
        cout << "ERROR: List is empty." << endl;
        position = -1;
    }
    return position;
}
template <typename T>
int LinkedList<T>::getSize() const {
    return size;
}
template <typename T>
void LinkedList<T>::print() const {
    Node* current = root->next;
    cout << "List: ";
    while(current != NULL) {
        cout << current->value << " ";
        current = current->next;
    }
    if(getSize() == 0) {
        cout << "Empty.";
    }
    cout << endl;
}
template <typename T>
void LinkedList<T>::reverse(Node* t_node) {
/*
    if(t_node == NULL) {
        reverse(root);
    } else

    if(t_node->next == NULL) {
        cout << "In (swapping): " << t_node->value << endl;
        root->next = t_node;
    } else {
        cout << "In: " << t_node->value << endl;
        Node* tmp = t_node->next;
        reverse(t_node->next);
        tmp->next = t_node;
    }
*/ //reverses list, but causes infinite loop in display
}
template <typename T>
int &LinkedList<T>::operator[](int pos) const {
    Node* current = root->next;
    if(pos <= size-1) {
        for(int i = 0; i < pos; i++) {
            current = current->next;
        }
    } else {
        cout << "ERROR: Out of bounds.";
        current = NULL;
    }
    return current->value;
}
template <typename T>
void LinkedList<T>::pop_back() {
    deleteNode(size-1);
}
template <typename T>
void LinkedList<T>::pop_front() {
    deleteNode(0);
}
template <typename T>
void LinkedList<T>::push_back(T val) {
    insertNode(size, val);
}
template <typename T>
void LinkedList<T>::push_front(T val) {
    insertNode(0, val);
}
#endif

//test driver
int main() {
    IntList i_list;
    int n;

    cout << "Appending node: value = " << 0 << endl;
    i_list.appendNode(0);
    i_list.print();
    cout << endl;

    n = 5;
    cout << "Inserting nodes (at their values). Node values = { ";
    for(int i = 0; i < n; i++) {
        cout << i << " ";
        i_list.insertNode(i,i);
    }
    cout << "}" << endl;
    i_list.print();
    cout << endl;

    cout << "Deleting node at position: " << i_list.getSize()-1 << endl;
    i_list.deleteNode(i_list.getSize()-1);
    i_list.print();
    cout << endl;

    cout << "Searching for value: " << 3 << endl;
    cout << "Found at: " << i_list.searchNode(3) << endl;
    cout << endl;

    i_list.print();
    cout << "List size: " << i_list.getSize() << endl;
    cout << endl;

    n = 3;
    cout << "Calling node at list[" << n << "]: " << i_list[n] << endl;
    cout << endl;

    i_list.print();
    cout << "Deleting node from back position." << endl;
    i_list.pop_back();
    i_list.print();
    cout << endl;

    i_list.print();
    cout << "Deleting node from front position." << endl;
    i_list.pop_front();
    i_list.print();
    cout << endl;

    n = 9;
    i_list.print();
    cout << "Adding node (value = " << n << ") to back position." << endl;
    i_list.push_back(n);
    i_list.print();
    cout << endl;

    n = 8;
    i_list.print();
    cout << "Adding node (value = " << n << ") to front position." << endl;
    i_list.push_front(n);
    i_list.print();
    cout << endl;

    i_list.print();
    cout << "Copying list to new list." << endl;

    IntList t_list(i_list);
    cout << endl;

    cout << "List copy:" << endl;
    t_list.print();
    cout << endl;

    /*
     * Showing functionality transfers over to LinkedList template class
     * generally, for primitive data types (lacks absolutely generality
     * for data which can't be passed directly to cout).
     */
    cout << "List functionality transfers generally to LinkedList class:" << endl;
    LinkedList<int> int_list;
    LinkedList<double> double_list;
    LinkedList<char> char_list;

    cout << "Appending nodes:" << endl;

    n = 5;
    for(int i = 0; i < n; i++){
        int_list.appendNode(i);
    }
    int_list.print();

    n = 5;
    for(int i = 0; i < n; i++){
        double_list.appendNode(i+0.1);
    }
    double_list.print();

    n = 5;
    for(int i = 0; i < n; i++){
        char_list.appendNode('A' + i);
    }
    char_list.print();

    cout << "Removing nodes:" << endl;

    n = 5;
    for(int i = 0; i < n; i++){
        int_list.pop_back();
    }
    int_list.print();

    n = 5;
    for(int i = 0; i < n; i++){
        double_list.pop_back();
    }
    double_list.print();

    n = 5;
    for(int i = 0; i < n; i++){
        char_list.pop_back();
    }
    char_list.print();

    return 0;
}

編輯 :我修改了我的算法,我相信它在算法上有效,但在功能上它可能正在做一些導致內存問題的事情。 我不確定為什么會這樣,但這里是:

void IntList::reverse() {
    IntList tmp(*this);
    int list_size = size;
    for(int i = 0; i < list_size; i++) {
        this->insertNode(i, tmp[tmp.getSize()-1]);
        this->pop_back();
        tmp.pop_back();
    }
}

事實上,如果我的[]運算符重載在這個方法中運行(由於某種原因它不是?)我可以取消tmp列表並直接引用列表中的最后一個值作為this[size-1]

這是什么問題?

你的問題是在reverse()之后,列表中的最后一個元素將指向根元素而不是指向null。 一種解決方案可能是明確檢查該條件,以便您獲得:

void IntList::reverse(Node* t_node) {
    if(t_node == NULL) {
        reverse(root);
        return;
    }

    if(t_node->next == NULL) {
        cout << "In (swapping): " << t_node->value << endl;
        root->next = t_node;
    } else {
        cout << "In: " << t_node->value << endl;
        Node* tmp = t_node->next;
        reverse(t_node->next);
        // If this node was the first node it will now be the last
        if (t_node == root) {
            tmp->next = NULL;
        } else {
            tmp->next = t_node;
        }
    }
}

如果應該可以反轉列表的子部分,那么這不起作用。 如果這是您需要的東西,那么您可能需要使用輔助函數來處理除第一個元素之外的所有元素。

假設我們有IntList {1,2,3},它實際上有這種形式:

0 -> 1 -> 2 -> 3

然后我們調用reverse(root) ,這樣t_noderoot具有相同的值(因此指向(0))。

Node* tmp = t_node->next;

所以tmp指向(1)。

reverse(t_node->next);

假設這是有效的,列表現在是0-> 1-> 3-> 2

tmp->next = t_node;

所以現在1-> 0。 該列表現在是一個循環,其他節點已丟失。

目前尚不清楚你打算做什么這個功能,但你必須誤解一些東西。

編輯:當您不了解低級別的機制時,您正在嘗試高級解決方案。

你的副本構造函數:

IntList(const IntList& list) { this->root = list.root; this->size = list.size; }

執行我們所謂的“淺拷貝”; 它復制指針成員,但不復制他們指向的東西。 如果您有一個如下所示的列表A

0->1->2->3

然后調用IntList B(A); ,你會得到這樣的東西:

   0
   |
   v
0->1->2->3

如果你然后調用A.pop_back()B.pop_back()你認為會發生什么?

更重要的是,你想做什么? 你想知道如何編寫遞歸函數,還是不再需要?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM