【蓝蓝计算机考研算法】-day05逆序输出链表

243 阅读4分钟

7.逆序输出链表数据

输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。

如输入{1,2,3}的链表如下图:

image.png
返回一个数组为[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;
}

运行结果

image.png

复杂度

  • 时间复杂度 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)