8、逆序输出链表。
输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。
如输入{1,2,3}的链表如下图:
返回一个数组为[3,2,1]
0 <= 链表长度 <= 10000
示例1
输入:
{1,2,3}
返回值:
[3,2,1]
示例2
输入:
{67,0,24,58}
返回值:
[58,24,0,67]
方法一
使用栈
思路
由于程序输入时的形式是中括号内包含数字的,所以先将输入的数据进行处理,changeChar方法中,第一个循环先利用数组,将中括号去掉,strtok() 函数将字符串按照逗号进行分割,atoi()再将分割出来的字符串转换为数字(后两个函数均为C标准库函数).接下来算法的处理方法就是对于声明的结构提,进行链表头节点和元素节点的创建,然后该方法使用栈的思想,顺序遍历链表的同时,将链表内的值入栈,当整个链表遍历完成之后,再进行出栈操作,同时,将所出栈的元素放入数组中遍历输出即可。
具体实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 10000
// 链表节点的结构体
struct ListNode {
int val;
struct ListNode *next;
};
// 栈的结构体
struct Stack {
struct ListNode* arr[MAXN];
int top;
};
// 初始化栈
void initStack(struct Stack *s) {
s->top = -1;
}
// 入栈
void push(struct Stack *s, struct ListNode *node) {
s->top++;
s->arr[s->top] = node;
}
// 出栈
struct ListNode* pop(struct Stack *s) {
if (s->top < 0) {
return NULL;
} else {
struct ListNode *node = s->arr[s->top];
s->top--;
return node;
}
}
// 计算链表长度
int getListLength(struct ListNode *head) {
int len = 0;
struct ListNode *p = head;
while (p != NULL) {
len++;
p = p->next;
}
return len;
}
// 将链表节点值存入数组并返回
int* reversePrint(struct ListNode* head, int* returnSize){
int len = getListLength(head); // 计算链表长度
int *res = (int*)malloc(sizeof(int) * len); // 动态分配数组内存
struct Stack s;
initStack(&s);
// 将链表节点入栈
struct ListNode *p = head;
while (p != NULL) {
push(&s, p);
p = p->next;
}
// 将栈中节点值存入数组
int i = 0;
while (s.top >= 0) {
struct ListNode *node = pop(&s);
res[i] = node->val;
i++;
}
*returnSize = len;
return res;
}
// 将输入的字符串转换为数组
int changeChar(char *str, int *num) {
int i,j=0;
for (i = 0; str[i] != '}'; i++) {
if (str[i] != '{') {
str[j++] = str[i];
}
}
str[j] = '\0'; // 确保新字符串以 '\0' 结尾
// 分割字符串并转换为数字
i = 0;
char *token = strtok(str, ",");
while (token != NULL) {
num[i++] = atoi(token);
token = strtok(NULL, ",");
}
return i;
}
// 测试
int main() {
char str[MAXN*2+2];
int num[MAXN];
int i;
scanf("%s", str);
int len = changeChar(str, num);
// 建立链表
struct ListNode *head = NULL, *p, *q;
for (i = 0; i < len; i++) {
p = (struct ListNode*)malloc(sizeof(struct ListNode));
p->val = num[i];
p->next = NULL;
if (head == NULL) {
head = p;
} else {
q->next = p;
}
q = p;
}
int returnSize = 0;
int *res = reversePrint(head, &returnSize);
// 输出结果
printf("[");
for (i = 0; i < returnSize; i++) {
printf("%d", res[i]);
if(i != returnSize-1)
printf(",");
}
printf("]\n");
// 释放内存
free(head);
free(p);
free(q);
free(res);
return 0;
}
方法二
使用递归
思路
大致内容与上述思路类似,只不过本方法的逆转使用的是递归的思想。
实现方法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 10000
struct ListNode {
int val;
struct ListNode *next;
};
int getListLength(struct ListNode* head) {
int len = 0;
while (head != NULL) {
len++;
head = head->next;
}
return len;
}
void getNodeValues(struct ListNode* head, int* arr, int* index) {
if (head == NULL) {
return;
}
getNodeValues(head->next, arr, index);
arr[(*index)++] = head->val;
}
int* reversePrint(struct ListNode* head, int* returnSize) {
int len = getListLength(head);
*returnSize = len;
int* arr = (int*)malloc(sizeof(int) * len);
int index = 0;
getNodeValues(head, arr, &index);
return arr;
}
// 将输入的字符串转换为数组
int changeChar(char *str, int *num) {
int i,j=0;
for (i = 0; str[i] != '}'; i++) {
if (str[i] != '{') {
str[j++] = str[i];
}
}
str[j] = '\0'; // 确保新字符串以 '\0' 结尾
// 分割字符串并转换为数字
i = 0;
char *token = strtok(str, ",");
while (token != NULL) {
num[i++] = atoi(token);
token = strtok(NULL, ",");
}
return i;
}
int main() {
char str[MAXN*2+2];
int num[MAXN];
scanf("%s", str);
int i;
int len = changeChar(str, num);
// 建立链表
struct ListNode *head = NULL, *p, *q;
for (i = 0; i < len; i++) {
p = (struct ListNode*)malloc(sizeof(struct ListNode));
p->val = num[i];
p->next = NULL;
if (head == NULL)
head = p;
else
q->next = p;
q = p;
}
// 调用函数,返回数组
int returnSize;
int* res = reversePrint(head, &returnSize);
printf("[");
for (i = 0; i < returnSize; i++) {
printf("%d", res[i]);
if(i != returnSize-1)
printf(",");
}
printf("]\n");
// 释放内存
free(head);
free(p);
free(q);
free(res);
return 0;
}
小结
今天算法的工作量确实大,按照题目所给的输入来计算确实有难度,而且为了使整个程序更容易理解整体思路,分开使用了两种方法。其实正常如果仅仅是逆序的话,不需要这么麻烦,可以将整个链表的元素顺序写入数组,一边写入一边计数,然后声明两个变量i和j,i从头开始,j从倒数位置开始两个位置交换,直到i>=j时停止循环。算是方法三吧很简便的一个方法实现逆序后数组输出。
算法部分代码如下,供大家参考
int* reversePrint(struct ListNode* head, int* returnSize) {
int* res = (int*)malloc(sizeof(int) * MAXN);
*returnSize = 0;
struct ListNode* p = head;
while (p != NULL) {
res[(*returnSize)++] = p->val;
p = p->next;
}
int i = 0, j = *returnSize - 1;
while (i < j) {
int temp = res[i];
res[i] = res[j];
res[j] = temp;
i++, j--;
}
return res;
}