題目:定義一個函數,輸入一個鏈表的頭結點,反轉該鏈表並輸出反轉後鏈表的頭結點。
在解決問題前,先想好測試用例:
1、功能測試:輸入的鏈表含有多個結點,鏈表中只有一個結點
2、特殊輸入測試:頭結點爲 NULL指針
解決這個問題有兩種方式:
前提:
這兩種方式 是以 頭結點並不是第一個數據節點 爲基準 表示的。
這種方式,頭結點並不保存鏈表的結點數據,其數據位只保存鏈表結點總數。
在輸出鏈表時,從頭結點後的第一個數據結點開始輸出,並不輸出頭結點。
方法:
1、頭插法:將頭結點後的鏈中結點 從前向後一個個斷開,並依次以頭插法插入在頭結點後,這樣也相當於完成了鏈表的反轉,鏈表的頭結點依然是原頭結點。
2、逆轉指針:即書上所闡述的方法。這種方法比較直觀,將每個結點的指向翻轉過來,原來指向後一結點的,現在指向前一個結點。
對於第二種方法,可以對照下圖來理解:
圖中闡述了一般情況下,即在鏈表中間,反轉一個結點的步驟。其他結點反轉的方式相同。
算法如下:
#include <iostream>
using namespace std;
typedef struct Node{
int m_nValue;
struct Node *m_pNext;
}ListNode;
/**創建空鏈表*/
ListNode * creat_List()
{
ListNode *pHead;
pHead = new ListNode;
pHead->m_nValue = 0; /**頭結點中保存數據節點總數*/
pHead->m_pNext = NULL;
return pHead;
}
/**在鏈表最後插入節點*/
ListNode * insert_Node_behind(ListNode *pHead,int pElem)
{
if(NULL == pHead)
{
cout << "頭結點爲空" << endl;
return pHead;
}
ListNode *temp, *current;
current = pHead;
while(NULL != current->m_pNext)
{
current = current->m_pNext;
}
temp = new ListNode;
temp->m_nValue = pElem;
temp->m_pNext = NULL;
current->m_pNext = temp;
pHead->m_nValue += 1;
return pHead;
}
/**遍歷輸出鏈表*/
void show_List(ListNode *pHead)
{
if(NULL == pHead)
{
cout << "頭結點爲空" << endl;
return;
}
ListNode *temp;
temp = pHead->m_pNext;
cout << "該 list 爲:" ;
while(NULL != temp)
{
cout << temp->m_nValue << ' ';
temp = temp->m_pNext;
}
cout << endl;
}
/**方法一:將頭結點後的鏈表,一個個斷開,以從前往後的方式,用頭插法依次接在頭結點後*/
ListNode * reverse_List_1(ListNode *pHead)
{
if(NULL == pHead || NULL == pHead->m_pNext)
{
return pHead;
}
ListNode *temp, *current;
current = pHead->m_pNext;
pHead->m_pNext = NULL; /**頭結點和後面的結點斷開*/
while(NULL != current)
{
temp = current->m_pNext;
current->m_pNext = pHead->m_pNext;
pHead->m_pNext = current;
current = temp;
}
return pHead;
}
/**方法二,改變指針方向*/
ListNode *reverse_List_2(ListNode *pHead)
{
if(NULL == pHead || NULL == pHead->m_pNext)
{
return pHead;
}
ListNode *pPre, *pCurr, *pNex;
//ListNode *temp = pHead;
/**設定三個指針的初始狀態*/
pCurr = pHead->m_pNext; /**保存當前結點*/
pNex = pCurr->m_pNext; /**保存當前結點的下一結點*/
pPre = NULL; /**保存當前結點的前一結點*/
//pHead->m_pNext = NULL;
//pHead = NULL;
while(NULL != pNex)
{
pCurr->m_pNext = pPre; /*反轉步驟*/
pPre = pCurr; /*更新步驟*/
pCurr = pNex;
pNex = pNex->m_pNext;
}
pCurr->m_pNext = pPre; /*將最後一個節點指向它的前一結點,防止鏈表斷裂*/
/** pNex = pPre; pCurr->m_pNext 和 pNex 雖然指的位置相同,但是並不是同一個指針,如果這樣寫會連接不起來 */
pHead->m_pNext = pCurr; /**將倒序後的結點鏈表,從新接頭結點後,這樣反轉後的頭結點依然是原來的頭結點,而第一個數據結點則變成了原來的尾結點*/
return pHead;
}
int main()
{
int n_of_list = 6;
int i = 1;
ListNode *pHead;
pHead = creat_List();
while(n_of_list > 0)
{
insert_Node_behind(pHead,i++);
n_of_list--;
}
show_List(pHead);
reverse_List_1(pHead);
show_List(pHead);
reverse_List_2(pHead);
show_List(pHead);
return 0;
}
結果如下:
以下是鏈表多結點情況,對於其他情況的測試(如單個結點,NULL指針等),可以改變代碼中的數據,來測試。
/*點滴積累,我的一小步O(∩_∩)O~*/