剑指Offer - 面试题6:从尾到头打印链表

简介: 剑指Offer - 面试题6:从尾到头打印链表

题目

输入一个链表的头节点,从尾到头反过来打印出来每个节点的值。链表节点定义如下:

struct ListNode
{
  int m_nKey;
  struct ListNode* m_pNext;
};


思路

栈方法

从尾到头完全符合栈的特性,我们直接拿栈来存储就可以顺利输出。(c语言需要自己构造栈,这块用数组代替。这里就只构造一个链表)

C

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
struct ListNode
{
  int m_nKey;
  struct ListNode* m_pNext;
};
/*  随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateListTail(struct ListNode** L, int n)
{
    struct ListNode* p;
    struct ListNode* r;
    int i;
    srand((unsigned int)time(NULL));                        /* 初始化随机数种子 */
    *L = (struct ListNode*)malloc(sizeof(struct ListNode)); /* L为整个线性表 */
    r = *L;                                      /* r为指向尾部的结点 */
    for (i = 0; i < n; i++)
    {
        p = (struct LilstNode*)malloc(sizeof(struct ListNode)); /*  生成新结点 */
        if (NULL == (*L))
        {
            perror("开辟子节点空间失败");
        }
        p->m_nKey = rand() % 10;                   /*  随机生成100以内的数字 */
        r->m_pNext = p;                          /* 将表尾终端结点的指针指向新结点 */
        r = p;                                   /* 将当前的新结点定义为表尾终端结点 */
    }
    r->m_pNext = NULL;                           /* 表示当前链表结束 */
}
/* 初始条件:链式线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
void ListTraverse(struct ListNode* L)
{
    struct ListNode* p = L->m_pNext;
    while (p != NULL)
    {
        printf("%d ", p->m_nKey);
        p = p->m_pNext;
    }
    printf("\n");
}
void PrintListReversing(struct ListNode* L)
{
    int* n = (int*)malloc(10 * sizeof(int));
    int size = 0;           //实际元素个数
    int length = 10;        //数组长度
    struct ListNode* p = L->m_pNext;
    while (p != NULL)
    {
        if (size + 1 == length)//扩容
        {
            length += 10;
            int* tmp = (int*)realloc(n, length * sizeof(int));
            if (NULL == tmp)
            {
                perror("扩充失败!");
            }
            n = tmp;
            tmp = NULL;
        }
        n[size++] = p->m_nKey;
        p = p->m_pNext;
    }
    for (int i = size - 1; i >= 0; i--)
    {
        printf("%d ", n[i]);
    }
}
int main()
{
  struct ListNode* L;
    CreateListTail(&L, 10);
    printf("从前到后打印\n");
    ListTraverse(L);
    printf("从尾到头打印\n");
    PrintListReversing(L);
  return 0;
}


C++

#include <string>
#include <iostream>
#include <stack>
using namespace std;
class Node
{
public:
  int data;
  Node* next;
};
class LinkList
{
public:
  LinkList();
  ~LinkList();
  int CreateLinkList(int size);
  int BYELinkList();
  int TravalLinkList();
  Node* head;
  int size;
};
LinkList::LinkList()
{
  head = new Node;
  head->data = 0;
  head->next = NULL;
  size = 0;
}
LinkList::~LinkList()
{
  delete head;
}
int LinkList::CreateLinkList(int n)//创建链表
{
  if (n < 0) {
    printf("error\n");
    return -1;
  }
  Node* ptemp = NULL;
  Node* pnew = NULL;
  this->size = n;
  ptemp = this->head;
  for (int i = 0; i < n; i++)
  {
    pnew = new Node;
    pnew->next = NULL;
    cout << "输入第" << i + 1 << "个节点值" << endl;
    cin >> pnew->data;
    ptemp->next = pnew;
    ptemp = pnew;
  }
  cout << "创建完成" << endl;
  return 0;
}
int LinkList::BYELinkList()//销毁链表
{
  Node* ptemp = NULL;
  if (this->head == NULL) {
    cout << "链表原本就为空" << endl;
    return -1;
  }
  while (this->head)
  {
    ptemp = head->next;
    delete head;
    head = ptemp;
  }
  cout << "销毁链表完成" << endl;
  return 0;
}
int LinkList::TravalLinkList()//输出链表
{
  Node* ptemp = this->head->next;
  if (this->head == NULL) {
    cout << "链表为空" << endl;
    return -1;
  }
  while (ptemp)
  {
    cout << ptemp->data << "->";
    ptemp = ptemp->next;
  }
  cout << "NULL" << endl;
  return 0;
}
void PrintListReversing(Node* list)//从尾到头打印
{
  stack<int> nodes;
  Node* ptemp = list->next;
  while (ptemp != NULL)
  {
    nodes.push(ptemp->data);
    ptemp = ptemp->next;
  }
  int temp = 0;
  cout << "从尾到头打印链表" << endl;
  while (nodes.empty() == false)//不为空
  {
    temp = nodes.top();
    cout << temp << " ";
    nodes.pop();
  }
  cout << endl;
}
int main(void)
{
  LinkList list;
  LinkList* plist = &list;
  plist->CreateLinkList(5);
  plist->TravalLinkList();
  PrintListReversing(plist->head);
  plist->BYELinkList();
  system("pause");
  return 0;
}

递归法

递归的本质就是栈结构,所以很自然的想到了用递归实现,我们访问到一个节点的时候,先递归输出后面的节点,在输出自身节点。

但是递归会有一个问题,当链表非常长的时候,就会导致函数调用的层级很深,从而导致函数调用栈溢出。显眼用栈基于循环实现的代码的鲁棒性要好一些。


C++

#include <string>
#include <iostream>
#include <stack>
using namespace std;
class Node
{
public:
  int data;
  Node* next;
};
class LinkList
{
public:
  LinkList();
  ~LinkList();
  int CreateLinkList(int size);
  int BYELinkList();
  int TravalLinkList();
  Node* head;
  int size;
};
LinkList::LinkList()
{
  head = new Node;
  head->data = 0;
  head->next = NULL;
  size = 0;
}
LinkList::~LinkList()
{
  delete head;
}
int LinkList::CreateLinkList(int n)//创建链表
{
  if (n < 0) {
    printf("error\n");
    return -1;
  }
  Node* ptemp = NULL;
  Node* pnew = NULL;
  this->size = n;
  ptemp = this->head;
  for (int i = 0; i < n; i++)
  {
    pnew = new Node;
    pnew->next = NULL;
    cout << "输入第" << i + 1 << "个节点值" << endl;
    cin >> pnew->data;
    ptemp->next = pnew;
    ptemp = pnew;
  }
  cout << "创建完成" << endl;
  return 0;
}
int LinkList::BYELinkList()//销毁链表
{
  Node* ptemp = NULL;
  if (this->head == NULL) {
    cout << "链表原本就为空" << endl;
    return -1;
  }
  while (this->head)
  {
    ptemp = head->next;
    delete head;
    head = ptemp;
  }
  cout << "销毁链表完成" << endl;
  return 0;
}
int LinkList::TravalLinkList()//输出链表
{
  Node* ptemp = this->head->next;
  if (this->head == NULL) {
    cout << "链表为空" << endl;
    return -1;
  }
  while (ptemp)
  {
    cout << ptemp->data << "->";
    ptemp = ptemp->next;
  }
  cout << "NULL" << endl;
  return 0;
}
void PrintListReversing(Node* list)//从尾到头打印
{
  if (NULL != list)
  {
    if (list->next != NULL)
    {
      PrintListReversing(list->next);
    }
    cout << list->data << " ";
  }
}
int main(void)
{
  LinkList list;
  LinkList* plist = &list;
  plist->CreateLinkList(5);
  plist->TravalLinkList();
  PrintListReversing(plist->head->next);
  plist->BYELinkList();
  system("pause");
  return 0;
}


本章完!

目录
相关文章
|
2月前
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
54 0
|
2月前
|
存储 算法 安全
HashMap常见面试题(超全面):实现原理、扩容机制、链表何时升级为红黑树、死循环
HashMap常见面试题:红黑树、散列表,HashMap实现原理、扩容机制,HashMap的jd1.7与jdk1.8有什么区别,寻址算法、链表何时升级为红黑树、死循环
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
54 5
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 18. 删除链表的节点
Leetcode题目"剑指 Offer 18. 删除链表的节点"的Python解决方案,通过使用双指针法找到并删除链表中值为特定数值的节点,然后返回更新后的链表头节点。
46 4
|
4月前
|
存储 算法 Python
【面试题】合井K个升序链表
【面试题】合井K个升序链表
36 0
|
4月前
|
存储 Java
【Java集合类面试十】、HashMap中的循环链表是如何产生的?
在多线程环境下,HashMap在扩容时如果发生条件竞争,元素的插入顺序可能形成循环链表,导致死循环。
|
4月前
|
安全 编译器 C++
【剑指offer】2.2编程语言(p22-p25)——面试题1:string赋值运算函数
【剑指offer】2.2编程语言(p22-p25)——面试题1:string赋值运算函数
|
6月前
|
存储 SQL 算法
LeetCode 83题:删除排序链表中的重复元素【面试】
LeetCode 83题:删除排序链表中的重复元素【面试】
|
7月前
【一刷《剑指Offer》】面试题 23:从上往下打印二叉树
【一刷《剑指Offer》】面试题 23:从上往下打印二叉树
|
7月前
【一刷《剑指Offer》】面试题 22:栈的压入、弹出系列
【一刷《剑指Offer》】面试题 22:栈的压入、弹出系列
下一篇
DataWorks