7.逆序输出链表数据
输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。
如输入{1,2,3}的链表如下图:
返回一个数组为[3,2,1]
0 <= 链表长度 <= 10000
示例
输入:{1,2,3}
返回值:{3,2,1}输入:{67,0,24,58}
返回值:{58,24,0,67}
思路
法一:利用头插法创建链表,再以此从头开始输出,便是逆序。
法二:由于程序输入时的形式是中括号内包含数字的,所以先将输入的数据进行处理,changeChar方法中,第一个循环先利用数组,将中括号去掉,strtok() 函数将字符串按照逗号进行分割,atoi()再将分割出来的字符串转换为数字(后两个函数均为C标准库函数).接下来算法的处理方法就是对于声明的结构提,进行链表头节点和元素节点的创建,然后该方法使用栈的思想,顺序遍历链表的同时,将链表内的值入栈,当整个链表遍历完成之后,再进行出栈操作,同时,将所出栈的元素放入数组中遍历输出即可。
具体实现——法一
#include <iostream>
using namespace std;
//定义链表节点
typedef struct LNode {
int data; // 数据域
LNode* next; // 指针域
LNode(int val) : data(val), next(nullptr) {}; // 构造函数
} LNode, * ListLink;
// 采用带虚拟头节点的头插法创建链表,用空格隔开各个节点数据,回车结束链表创建
ListLink ListHeadInsert1() {
LNode* dummyHead = new LNode(-1), * s, * tmp; // 虚拟头节点(统一插入操作) 待插入新节点指针 临时节点指针
int val;
char ch; // 待插入节点的数据
while (cin >> val) {
s = new LNode(val); // 创建待插入的新节点
s->next = dummyHead->next; // 插入节点
dummyHead->next = s;
if ((ch = cin.get()) == '\n') break; // 结束条件
};
tmp = dummyHead->next; // 真正的头节点
delete dummyHead; // 释放虚拟头节点
return tmp; // 返回真正的头节点
}
// 测试一下
int main() {
ListLink L = ListHeadInsert1(); // 创建链表
LNode* cur = L; // 遍历指针
while (cur) { // 遍历打印节点
cout << cur->data << ' ';
cur = cur->next;
}
return 0;
}
具体实现——法二
#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;
}
运行结果
复杂度
- 时间复杂度 O(n)--- 创建链表的时间复杂度为O(n)
- 空间复杂度 O(1)--- 链表属于必要空间,除此无额外的辅助空间
小结
今天对编辑器的耐心已经忍到临界值了。线上编辑器又没有输入提示 ,得花时间搞定编辑器,才能真的思考题目了。本次代码抄作业的,直接一模一样敲打了一遍,需要重点复习,C语言编写的在VS2022上报这样的错误“C4996 'strtok': This function or variable may be unsafe. Consider using strtok_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. day044 D:\代码\day044\day044\day044.cpp 90 ”
抄这两位大神的蓝蓝计算机考研算法-day05反转输出链表 - 掘金 (juejin.cn)[蓝蓝计算机考研算法训练二期]-day05 - 掘金 (juejin.cn)