逆序单链表的高效算法
链表反转是很多笔试面试常考之题,既然这么常见那就好好研究下。其实链表反转方法很多,主要有一下几种办法:
1、重建新链表,使用头插法将原链表元素放入,时空复杂度较大,同时如果加入“就地逆序不新建”等限制条件,该算法便不可用;
2、堆栈法:将原链表元素依序push如堆栈中,然后再pop入新链表中,时空复杂度依然过大,但是思路不错;
3、修正的头插法: 对方法1的头插法进行改进,不插入新建列表中,而是插入已置空的当然链表中,只修改各节点的next指向,时间复杂度只有O(n)。是较为完美的解决方案。
总结:其实还存在一些变形的算法,比如笔者刚开始开始自制了一种类似头插法的算法,不过需要增加一个零时指针保存当前指针在原链表中的next节点,时间复杂度同算法3是相同的,但是在参考了一些数据结构书后发现这三种算法相对思路更加清晰更“规范”些。尤其是算法三。
有了以上讨论,写出反转链表的算法就很容易了,以下是算法3的C语言实现:
1、重建新链表,使用头插法将原链表元素放入,时空复杂度较大,同时如果加入“就地逆序不新建”等限制条件,该算法便不可用;
2、堆栈法:将原链表元素依序push如堆栈中,然后再pop入新链表中,时空复杂度依然过大,但是思路不错;
3、修正的头插法: 对方法1的头插法进行改进,不插入新建列表中,而是插入已置空的当然链表中,只修改各节点的next指向,时间复杂度只有O(n)。是较为完美的解决方案。
总结:其实还存在一些变形的算法,比如笔者刚开始开始自制了一种类似头插法的算法,不过需要增加一个零时指针保存当前指针在原链表中的next节点,时间复杂度同算法3是相同的,但是在参考了一些数据结构书后发现这三种算法相对思路更加清晰更“规范”些。尤其是算法三。
有了以上讨论,写出反转链表的算法就很容易了,以下是算法3的C语言实现:
#include <stdio.h>
#include <stdlib.h>
#define LINK_LENGTH 15
typedef struct _Node
{
int data;
struct _Node *next;
}Node, *NodePtr;
void CreateLinklist(NodePtr pHead)
{
NodePtr pPrev, pCurr;
int i = 0;
pPrev = pHead;
for(i = 0; i < LINK_LENGTH; i++)
{
pCurr = (NodePtr)malloc(sizeof(Node));
pCurr->data = i + 1;
pCurr->next = NULL;
pPrev->next = pCurr;
pPrev = pCurr;
}
}
void ReverseLinklist(NodePtr pHead)
{
NodePtr pCurr, pTmp;
pCurr = pHead->next;
pHead->next = NULL; // Empty the original linklist
while(pCurr != NULL)
{
pTmp = pCurr->next;
// Insert to head
pCurr->next = pHead->next;
pHead->next = pCurr;
pCurr = pTmp;
}
}
void PrintLinklist(NodePtr pHead)
{
NodePtr pCurr = pHead->next;
while(pCurr != NULL)
{
printf("%d ", pCurr->data);
pCurr = pCurr->next;
}
printf("\n");
}
int main()
{
NodePtr pHead = NULL;
pHead = (NodePtr)malloc(sizeof(Node));
pHead->data = -1; // Head always not in real linklist.
pHead->next = NULL;
CreateLinklist(pHead);
printf("Original Linklist: ");
PrintLinklist(pHead);
// Reverse
ReverseLinklist(pHead);
printf("Reversed Linklist: ");
PrintLinklist(pHead);
system("pause");
return 0;
}
#include <stdlib.h>
#define LINK_LENGTH 15
typedef struct _Node
{
int data;
struct _Node *next;
}Node, *NodePtr;
void CreateLinklist(NodePtr pHead)
{
NodePtr pPrev, pCurr;
int i = 0;
pPrev = pHead;
for(i = 0; i < LINK_LENGTH; i++)
{
pCurr = (NodePtr)malloc(sizeof(Node));
pCurr->data = i + 1;
pCurr->next = NULL;
pPrev->next = pCurr;
pPrev = pCurr;
}
}
void ReverseLinklist(NodePtr pHead)
{
NodePtr pCurr, pTmp;
pCurr = pHead->next;
pHead->next = NULL; // Empty the original linklist
while(pCurr != NULL)
{
pTmp = pCurr->next;
// Insert to head
pCurr->next = pHead->next;
pHead->next = pCurr;
pCurr = pTmp;
}
}
void PrintLinklist(NodePtr pHead)
{
NodePtr pCurr = pHead->next;
while(pCurr != NULL)
{
printf("%d ", pCurr->data);
pCurr = pCurr->next;
}
printf("\n");
}
int main()
{
NodePtr pHead = NULL;
pHead = (NodePtr)malloc(sizeof(Node));
pHead->data = -1; // Head always not in real linklist.
pHead->next = NULL;
CreateLinklist(pHead);
printf("Original Linklist: ");
PrintLinklist(pHead);
// Reverse
ReverseLinklist(pHead);
printf("Reversed Linklist: ");
PrintLinklist(pHead);
system("pause");
return 0;
}