反转链表(reverse a lnked list)

来源:互联网 发布:软件架构设计图 编辑:程序博客网 时间:2024/06/18 18:52

今天, 看到如下几个面试题。

问题一:

对于一个单项链表, 编写一个函数, 把给定的单项链表进行反转。 即最后一个元素变成新链表的第一个元素...。

例如下图:

 

第一个field为节点存放的数据, 第二个field指的是存放下一个node的地址, head指向链表头。 反转之后, 得到新的链表如下:

解决办法:

我们可以遍历链表, 对于每一个当前的节点, 我们可以调整(adjust)当前的node的link part,让其指向之前的节点(previous node), 并且存下下一个(next)node。

 我们的节点的数据结构如下:

struct Node {    int data;    Node* next;};Node* pHead; // pointer to the linked list

反转程序如下:

Node* Reverse(Node* pHead) {    if(pHead == NULL) return pHead;        Node *pCur = pHead, *pPrev = NULL, *pNext;    while(pCur != NULL) {        pNext = pCur -> next;        pCur -> next = pPrev;        pPrev = pCur;        pCur = pNext;    }    pHead = prev;    return pHead;}

问题二:

反向一个string。

关于反向打印链表(这里是单向链表), 之前有提到, 但是采用的是递归的办法打印。

这里使用stack进行反向。 对于C的string, 结束标志是'/0', 注意C中'/0'不是string的一部分, 只是标志着string的结束。

我们可以遍历这个string, 将访问到的每一个字符存到一个stack之中。 遍历完成之后, 我们只需要top stack中的元素, 然后调用pop即可实现reverse的操作。




 

#include <iostream>#include <stack>#include <cstring>using namespace std;void Reverse(char C[], int n){   stack<char> S;   for(int i = 0; i < n; ++i) {    S.push(C[i]);   }   for(int i = 0; i < n; ++i) {        C[i] = S.top(); // overwrite        S.pop(); // perform pop   }}int main(){    char C[] = "hello w"; // 会补个'/0'    Reverse(C, strlen(C));    cout << "string: ";    for(int i = 0; i < static_cast<int>(strlen(C)); ++i)        cout << C[i];}


运行结果:

时间复杂度: O(n)

空间复杂度: O(n)

n表示字符的元素个数。

 

更好的解决办法:

使用两个变量, 一个记录着字符串的首元素, 一个记录字符串的末尾元素, 二者同时向中间移动, 交换, 直至二者相遇为止。

 

#include <iostream>#include <cstring>using namespace std;void Reverse(char C[], int n){    for(int i = 0, j = n - 1; i <= j; ++i, --j) {        swap(C[i], C[j]);    }}int main(){    char C[] = "hello w"; // 会补个'/0'    Reverse(C, strlen(C));    cout << "string: ";    for(int i = 0; i < static_cast<int>(strlen(C)); ++i)        cout << C[i];}


对于单向链表而言, 可以使用递归反向打印, 但是递归开销太大。 也可以使用stack进行reverse。 这样比较好的。 总体思想是遍历, 存到stack中,然后top, 然后pop。

0 0
原创粉丝点击