本文轉自:http://chaishushan.blog.163.com/blog/static/130192897200911725838630/
假設鏈表的結構爲:
struct Node { int item; Node* next; };
單向鏈表是一個有序的序列.假設有一個單向鏈表A:
1, 2, 3, 4, 5, ...
現在將A表逆序後得到鏈表B:
..., 5, 4, 3, 2, 1
// 常規的反轉鏈表方法
Node *reverse(Node *list)
{
link t, y = list, r = 0;
while (y != 0) { t = y->next; y->next = r; r = y; y = t; }
return r;
}
其實上面的這個操作自然地對應於棧的出棧/壓棧操作.
因此, 單向鏈表的逆序問題我們也可以抽象爲A和B兩個
棧的轉換問題.
現在給Node實現用於棧的操作函數:
// 1. 判斷棧是否爲空
bool isEmpty(Node* stack)
{
return (stack == NULL);
}
// 2. 向棧stack中壓入一個node元素
void push(Node* &stack, Node* node)
{
node->next = stack;
stack = node;
}
// 3. 從棧stack中彈出一個元素
Node* pop(Node* &stack)
{
assert(!isEmpty(stack));
Node *t = stack;
stack = stack->next;
return t;
}
下面可以基於棧實現單向鏈表的逆序操作了.
Node *reverse(Node *oldList)
{
Node *newList = NULL;
while(!isEmpty(oldList))
{
push(newList, pop(oldList));
}
return newList;
}
採用棧的思維來思考單向鏈表的逆序問題之後,許多本來
相對複雜的問題都會變得異常簡單. 例如, 我們現在再
考慮用遞歸的方法來逆序鏈表.
// 遞歸實現反轉鏈表
Node *reverse(Node *oldList, Node *newList=NULL)
{
// 判斷oldList是否爲空
if(isEmpty(oldList)) return newList;
// 從oldList棧彈出一個元素
// 然後將彈出的元素壓到newList棧中
push(newList, pop(oldList));
// 遞歸處理剩下的oldList鏈表
return reverse(oldList, newList);
}
// 遞歸版本的調用方式
int main()
{
Node *list = NULL;
// newList採用默認的NULL
Node *t = reverse(list);
// ...
}
另一種遞歸方法:
node* reverse( node* pNode, node*& head)
{
if ( (pNode == NULL) || (pNode->next == NULL) ) // 遞歸跳出條件
{
head = pNode; // 將鏈表切斷,否則會形成迴環
return pNode;
}
node* temp = reserve(pNode->next, head);// 遞歸
temp->next = pNode;// 將下一節點置爲當前節點,既前置節點
return pNode;// 返回當前節點
}