//反转链表
//迭代的
//递归的
原题
运行结果
迭代的思路
空间换时间,创建一个顺序表储存所有的链表地址
整体思路:创建一个指针使其遍历到链表最后,期间记录经过的节点地址
如图
迭代代码如下:
时间复杂度O(n)
空间复杂度O(n)
struct ListNode* reverseList(struct ListNode* head)
{
if (head == NULL)
{
return head;
}
int capacity = 10;//顺序表容量
struct ListNode** all_p = (struct ListNode**)malloc(sizeof(struct ListNode*) * capacity);
//在堆上开辟一块空间
//这块空间的大小为一个地址的大小(4字节)
//即模拟实现一个指针数组
struct ListNode* back = NULL;//后面的指针
struct ListNode* end = NULL;//最后面的指针
int count = 0;//计节点数
back = head;
while (back->next)//使后面的指针指向链表最后一个节点//并且记录所有的节点
{
if (count >= capacity - 2)//顺序表扩容
{
all_p = (struct ListNode**)realloc(all_p, sizeof(struct ListNode*) * (capacity *= 2));
//结构体指针数组扩容
}
all_p[count] = back;//把所有的链表地址记录在一个指针数组中,并依据序排列
back = back->next;
count++;
}
//循环结束时back是最后一个节点的地址
//count是节点数 - 1
//因为指针数组中,链表的最后一个地址没有记录
//最后的有效数组下标为count- 1
end = back;
while (back != head)//把记录下来的地址写回去
{
back->next = all_p[count - 1];//倒着放回
back = back->next;//倒着访问
count--;
}
back->next = NULL;
return end;
}
用于测试的创建的链表
int main()
{
struct ListNode* test1 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test2 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test3 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test4 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test5 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test6 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test7 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test8 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test9 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test10 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test11 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test12 = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* test13 = (struct ListNode*)malloc(sizeof(struct ListNode));
test12->val = 12;
test12->next = NULL;
test11->val = 11;
test11->next = test12;
test10->val = 10;
test10->next = test11;
test9->val = 9;
test9->next = test10;
test8->val = 8;
test8->next = test9;
test7->val = 7;
test7->next = test8;
test6->val = 6;
test6->next = test7;
test5->val = 5;
test5->next = test6;
test4->val = 4;
test4->next = test5;
test3->val = 3;
test3->next = test4;
test2->val = 2;
test2->next = test3;
test1->val = 1;
test1->next = test2;
test13 = reverseList(test1);
return 0;
}
递归思路如下
当为空链表和单链表时直接输出结果
只有两个链表的时候,只需要交换这两个链表的next
所以程序需要递归到只有一个链表的时候,
回归后
用提前保存之前的地址的之后的地址交换
如图
递归时head=tmp,从左向右
但回归时
tmp刚好是head的上一个地址
所以,直接把tmp的地址放在head->next 就成功逆序了链表
代码如下
时间复杂度O(N)
空间复杂度O(n)
struct ListNode* end = NULL;
struct ListNode* tmp = head;//记录当前的地址
static int count = 0;//记录节点数
int flag = 0;//标记第一次递归
if (count == 0)
{
flag = 1;
}
if (head == NULL)//没有节点
{
return head;
}
else if (head->next == NULL)//只有一个节点
{
count++;//最后一个也要计数
return head;
}
else//至少有两个节点
{
head = head->next;//头的地址改为下一个节点
count++;//每次递归都会改变count的值,其值等于第几个节点,只有第一次为1
end = reverseList(head);
//if (head->next == NULL)//最后一个节点不会来到这里,所以需要倒数第二个节点进行处理最后一个节点
//{
// head->next->next = tmp;
//}
head->next = tmp;//此时head已经是原来头地址的下一个地址,所以只要把源地址放入
}
if (flag)//第一次开始递归时的节点next置为空
{
tmp->next = NULL;
}
return end;