[英]Reversing a Link List using Iterative Approach
我的反轉鏈表的代碼有什么問題?
void rev(node* &head)
{
int flag=0;
node* head1=NULL;
while(head->next!=NULL)
{
node* temp1=head;
node* temp2=head;
while(temp1->next!=NULL)
{
temp2=temp1;
temp1=temp1->next;
}
if(flag==0)
{
head1=temp1;
flag++;
}
temp1->next=temp2;
temp2->next=NULL;
}
head=head1;
delete head1;
}
我試圖解決反轉鏈接列表的標准問題。 所以我嘗試實施這種方法,但它似乎進入了無限循環,我無法理解為什么。
您的 function 無效。
例如,傳遞的指針head
可以等於nullptr
。 在這種情況下,這個 while 循環
while(head->next!=NULL)
已經可以調用未定義的行為。
或者列表中沒有要刪除的內容但是 function 有這些語句
head=head1;
delete head1;
那沒有意義。
即使通過調用 delete 刪除語句,這也不會使 function 正確。 例如,如果列表只包含一個節點,那么這個 while 循環
while(head->next!=NULL)
不會被執行。 結果,由於循環后的這條語句,指針head
將設置為NULL
head=head1;
因為在循環之前指針head1
被設置為NULL
node* head1=NULL;
也似乎在這個嵌套的 while 循環中
while(temp1->next!=NULL)
{
temp2=temp1;
temp1=temp1->next;
}
您正試圖在列表中找到至少效率低下的最后一個節點。
而你的function不清楚,太復雜了。
要編寫 function,學習 header <functional>
中聲明的標准 C++ function std::exchange
就足夠了,這將使 function 的代碼更加簡單明了。
下面是一個演示程序,展示了如何實現 function 反轉單鏈表。
#include <iostream>
#include <functional>
#include <iterator>
struct node
{
int data;
node *next;
};
void clear( node * &head )
{
while ( head ) delete std::exchange( head, head->next );
}
void assign( node * &head, const int a[], size_t n )
{
clear( head );
for (node **current = &head; n--; current = &( *current )->next)
{
*current = new node{ *a++, nullptr };
}
}
std::ostream & display( const node *const &head, std::ostream &os = std::cout )
{
for (const node *current = head; current != nullptr; current = current->next)
{
os << current->data << " -> ";
}
return os << "null";
}
void reverse( node * &head )
{
for ( node *current = head, *previous = nullptr; current != nullptr; previous = head )
{
head = std::exchange( current, current->next );
head->next = previous;
}
}
int main()
{
node *head = nullptr;
const int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
assign( head, a, std::size( a ) );
display( head ) << '\n';
reverse( head );
display( head ) << '\n';
clear( head );
}
程序 output 是
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 -> null
可以看到function只有一個for循環,其復合語句只包含兩條語句
void reverse( node * &head )
{
for ( node *current = head, *previous = nullptr; current != nullptr; previous = head )
{
head = std::exchange( current, current->next );
head->next = previous;
}
}
如果不使用標准 function std::exchange
,則反轉列表的 function 將多一個語句,例如
void reverse( node * &head )
{
for ( node *current = head, *previous = nullptr; current != nullptr; previous = head )
{
head = current;
current = current->next;
head->next = previous;
}
}
首先,一個迷你代碼審查:
//
// Bigger issues implied by this function are that it is not a very good
// linked list, likely an extremely basic C-style list. However, that is
// beyond the scope of this question.
//
void rev(node* &head)
{
int flag=0; // Unnecessary
node* head1=NULL; // Prefer nullptr
while(head->next!=NULL)
{
node* temp1=head;
node* temp2=head; // Choose better names
while(temp1->next!=NULL) // Traverse the entire list at every iteration
{
temp2=temp1;
temp1=temp1->next;
}
if(flag==0)
{
head1=temp1;
flag++;
}
temp1->next=temp2; // Always and only swaps the last two elements
temp2->next=NULL;
// Never updates head in the loop; loop is infinite
}
head=head1;
delete head1; // head1 was pointing to a valid node; you just nuked your
// entire list
}
該算法非常簡單,當用紙和鉛筆畫出問題時,它就會自動顯示出來。 你只需要讓箭頭指向另一個方向,然后重新分配頭部。 您正在嘗試這樣做,但除了最后兩個節點外,您沒有更改任何指針。 您需要在列表中移動時更改它們。
不需要特殊的head
檢查和flag
。 您自然會到達尾部,並且可以在這樣做時重新分配頭部。
這是重新設計的算法:
#include <iostream>
struct node {
int data;
node* next;
node(int d) : data(d), next(nullptr) {}
};
//
// Bigger issues implied by this function is that it is not a very good
// linked list, likely an extremely basic C-style list. However, that is
// beyond the scope of this question.
//
void rev(node*& head) {
node* prev = nullptr;
node* curr = head;
node* next = nullptr; // Not immediately assigned to account for
// empty list.
while (curr) {
next = curr->next; //
curr->next = prev; // This order of operations is very important
prev = curr; //
curr = next; //
}
head = prev;
}
int main() {
node* list = new node{1};
list->next = new node{2};
list->next->next = new node{3};
list->next->next->next = new node{4};
list->next->next->next->next = new node{5};
node* walker = list;
std::cout << "Original list: ";
while (walker != nullptr) {
std::cout << walker->data << ' ';
walker = walker->next;
}
std::cout << '\n';
rev(list);
std::cout << "Reversed list: ";
walker = list;
while (walker != nullptr) {
std::cout << walker->data << ' ';
walker = walker->next;
}
std::cout << '\n';
// On the one hand, I don't delete my nodes. On the other,
// the program is ending and the OS will clean up my mess.
// This is generally a bad practice.
}
Output:
❯ ./a.out
Original list: 1 2 3 4 5
Reversed list: 5 4 3 2 1
雖然它需要更多代碼,但強烈建議使用正確的 C++ 鏈表 class 以避免main()
中所需的徹頭徹尾的愚蠢初始化。
而且我知道這段代碼很可能只是為了理解這個特定的算法,但是 C++ 標准庫確實提供了單鏈表和雙向鏈表,這兩種鏈表都很容易逆向。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.