题目描述
输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
5种思路
(1)头插法(改变了链表的方向,即是重新定义了一个方向相反的链表)
(2)利用栈先入后出的特性完成
(3)存下来然后进行数组翻转。
(4)递归
(5)链表就地反转(更改链表的结构,实现链表的逆序,相比数组逆序复杂)
基础知识:
https://www.cnblogs.com/mark2018/p/9374403.html
struct ListNode {
int val; //定义val变量值,存储节点值
struct ListNode *next; //定义next指针,指向下一个节点,维持节点连接
}
- 在节点ListNode定义中,定义为节点为结构变量。
- 节点存储了两个变量:value 和 next。value 是这个节点的值,next 是指向下一节点的指针,当 next 为空指针时,这个节点是链表的最后一个节点。
- 注意注意val只代表当前指针的值,比如p->val表示p指针的指向的值;而p->next表示链表下一个节点,也是一个指针。
- 构造函数包含两个参数 _value 和 _next ,分别用来给节点赋值和指定下一节点
参考:
C++ list 容器
https://www.cnblogs.com/ckings/p/3677561.html
1.头插法
https://blog.csdn.net/Ding_xiaofei/article/details/80530190
编译通过
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* listNode) {
// 头插法构建逆序链表
ListNode* head = new ListNode(-1);//创建一个什么样的元素呢?-1改为0 编译也通过,创建一个新的元素
while (listNode != NULL)
{
ListNode* memo = listNode->next;//1
listNode->next = head->next;//2
head->next = listNode;//3
listNode = memo;//4
//其中的1和4相当于对原来的listNode 每次向右移动一个结点 memo相当于一个暂存链表指针变量,赋给它的值可以实现指向一个新的链表
// 2和3相当于使用新的listNode结点头插在head的新链表中
}
// 构建 ArrayList
vector<int> ret;//可变容器
head = head->next;//指向下一个结点
while (head != NULL) {
ret.push_back(head->val);
head=head->next;
}
return ret;
}
};
注意上面程序中出现:打印时需要head=head->next 是为了指向第一个结点,如下区分头结点和第一个结点
草稿:
头插法见:
头插法: 每次都让新结点在前面
//创建一个n个结点的链表L
void CreateListHead(LinkList *L,int n)
{
LinkList p;
int i;
srand(time(0));
*L=(LinList)malloc(sizeof(Node));
(*L)->next=NULL;//只有头结点
for(i=0;i<n;i++)
{
p=(LinkList)malloc(sizeof(Node));
p->data=rand()%100+1;
p->next=(*L)->next;
(*L)->next=p;//在表头插入
}
}
明白!
2.压栈
class Solution
{
public:
vector<int> printListFromTailToHead(ListNode* head)//向量容器可以放置很多变量
{
vector<int> value;//向量
ListNode *p=NULL;
p=head;
stack<int> stk;//栈
while(p!=NULL) //将链表值压栈
{
stk.push(p->val);
p=p->next;
}
while(!stk.empty())//出栈到容器value中
{
value.push_back(stk.top());
stk.pop();
}
return value;
}
};
3.链表值存下来并进行数组翻转
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head)
{
vector<int> value;//定义一个动态数组
ListNode *p=NULL;
p=head;
while(p!=NULL)
{
value.push_back(p->val);//在数组的最后添加一个数据
p=p->next;
}
//reverse(value.begin(),value.end()); //C++自带的翻转函数
int temp=0;
int i=0,j=value.size()-1;
while(i<j)
{
temp=value[i]; //swap函数,swap(value[i],value[j]);
value[i]=value[j];
value[j]=temp;
i++;
j--;
}
return value;
}
};
4、递归(类似于压栈,找到最后一个位置的值并逐个的往前返回,之前的递归函数还没有运行)
class Solution
{
public:
vector<int> value;
vector<int> printListFromTailToHead(ListNode* head)
{
ListNode *p=NULL;//定义一个链表
p=head;
if(p!=NULL)//递归最关键的是基线条件和递归条件
{
if(p->next!=NULL)//下一个指向为空说明上一个判断找到的是链表的最后一个位置
{
printListFromTailToHead(p->next);
}
value.push_back(p->val);
}
return value;
}
};
5.链表就地反转
一次反转相当于执行两次操作:先删除一个结点,再将删除的结点插入到头结点与指向的下一个结点之间
参考:http://www.cnblogs.com/byrhuangqiang/p/4311336.html
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
ListNode* Head1=new ListNode(-1);
//if (head==NULL)
// return head;
ListNode* dummy=new ListNode(-1);
dummy->next=head;
ListNode* prev=dummy->next;
ListNode* pCur=prev->next;
while (pCur!=NULL) {
prev->next=pCur->next;
pCur->next=dummy->next;
dummy->next=pCur;
pCur=prev->next;
}
// 构建 ArrayList
vector<int> ret;
Head1=dummy->next;
while(Head1!=NULL) {
ret.push_back(Head1->val);
Head1=Head1->next;
}
return ret;
}
};
//错误
不通过
您的代码已保存
段错误:您的程序发生段错误,可能是数组越界,堆栈溢出(比如,递归调用层数太多)等情况引起
case通过率为0.00%
为此需要定义三个指针
C++相关:
https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html