剑指offer--面试题5

到现在为止,看过的书+代码有一定量了,并且也参加了个比赛,给自己的总体感觉:编程需要的是灵活的头脑,书里的东西只是讲个规则、思想,其实际实现可以千差万别!   潜在的规则+灵活的思维 = 程序!

在做面试题5时,发现Utilities文件夹下的内容太好了,基本上是那些数据结构的实现:链表、二叉树、树等(缺个图),准备通过学习这些代码来深入理解各个数据结构及其接口/成员函数。

拿该题来说,解决单链表!!!

题目:逆序打印单链表

一、自己写单链表类及其操作

花了一下午时间,无语了。。。

1、List.h

//单链表数据结构及基本操作

//最大节点数
const int MAXLENGTH = 50;
//节点
struct ListNode
{
    int m_Value;
    ListNode* m_pNext;
};

//List类
class List
{
private:
    ListNode LNode;
    int MaxLength;
public:
    //constructor and deconstructor
    List();
    virtual ~List();
    //单链表操作
    //1. 创建节点
    ListNode* CreateListNode(int value);
    //2. 创建链表或者将节点加到链尾
    void CreateFrontOrAddToTail(ListNode** pHead, int value);
    //3. 在第i个节点之前插入新的节点
    void ListInsert(ListNode* pHead, int i, int value);
    //4. 删除value=e的节点
    void RemoveListNode(ListNode** pHead,int value);
    //5. 查找第一个value=e的节点
    int FindListNode(ListNode* pHead,int value);
    //6. 销毁链表
    void DestoryList(ListNode* pHead);
    //7. 链表元素个数
    int ListLength(ListNode* pHead);
};

2、List.cpp

//List.cpp

#include "List.h"
#include <iostream>

List::List()
{
    LNode.m_Value = 0;
    LNode.m_pNext = NULL;
    MaxLength = MAXLENGTH;
}

List::~List()
{

}

    //1. 创建节点
ListNode* List::CreateListNode(int value)
{
    ListNode* pNew = new ListNode;
    pNew->m_Value = value;
    pNew->m_pNext = NULL;
}
    //2. 创建链表或者将节点加到链尾
void List::CreateFrontOrAddToTail(ListNode** pHead, int value)
{
    if(pHead == NULL)
        return;
    ListNode* pNew = CreateListNode(value);
    if(*pHead == NULL) //空链表
        *pHead = pNew;
    else
    {
        ListNode* pNode = *pHead;
        while(pNode->m_pNext != NULL)
            pNode = pNode->m_pNext;
        pNode->m_pNext = pNew;
    }

}
    //3. 在第i个节点之前插入新的节点
void List::ListInsert(ListNode* pHead, int i, int value)
{
    if(pHead == NULL || i >= MaxLength)
        return;
    ListNode* pNew = CreateListNode(value);
    ListNode* pNode = *pHead;
    ListNode* preNode = *pHead;
    i--;
    while(i && pNode->m_pNext != NULL)
    {
        preNode = pNode;
        pNode = pNode->m_pNext;
        i--;
    }
    if(i == 0)
    {
        preNode->m_pNext = pNew;
        pNew->m_pNext = pNode;
    }
    else
        cout<<"Failed!"<<endl;
}
    //4. 删除value=e的第一个节点
bool List::RemoveListNode(ListNode** pHead,int value)
{
    if(pHead == NULL || *pHead == NULL)
        return false;
    ListNode* pToBeDeleted = NULL;
    if((*pHead)->m_Value == value)
    {
        pToBeDeleted = *pHead;
        *pHead = (*pHead)->m_pNext;
    }
    else
    {
        ListNode* pNode = *pHead;
        while(pNode->m_pNext != NULL && pNode->m_pNext->m_Value != value)
            pNode = pNode->m_pNext;
        if(pNode->m_pNext != NULL && pNode->m_pNext->m_Value == value)
        {
            pToBeDeleted = pNode->m_pNext;
            pNode->m_pNext = pNode->m_pNext->m_pNext;
        }
    }
    if(pToBeDeleted != NULL)
    {
        delete pToBeDeleted;
        pToBeDeleted = NULL;
        return true;
    }
        return false;
}

    //5. 查找第一个value=e的节点,返回其位置
int List::FindListNode(ListNode* pHead,int value)
{
    int i = 1;
    ListNode* pNode = pHead;
    while(pNode != NULL && pNode->m_Value != value)
    {
        i++;
        pNode = pNode->m_pNext;
    }
    if(pNode != NULL && pNode->m_Value == value)
        return i;
    else
        return 0;

}
    //6. 销毁链表
void List::DestoryList(ListNode* pHead)
{
    ListNode* pNode = pHead;
    while(pHead != NULL)
    {
        pNode = pHead;
        pHead = pHead->m_pNext;
        delete pNode;
    }
}
    //7. 链表元素个数
int List::ListLength(ListNode* pHead)
{
    ListNode* pNode = pHead;
    int i = 0;
    while(pNode != NULL)
    {
        i++;
        pNode = pNode->m_pNext;
    }
    return i;
}

未测试过。。。因为想继续做面试题5了,进度太慢了!!!

二、面试题5整理:

 逆序打印单链表,首先想到的便是通过扫描链表,并同时用栈存储每个值,最后利用栈的LIFO特点打印即可。但是,鉴于自己的水平,并没有用过C++中stl里的stack,因此想了另一种方法,即将扫描链表时所得到的值存入到一个数组中,最后逆序打印即可。这种方法固然可行,但效率上必然低于栈的。所以综合以上分析,又学习了stl中的stack,具体见上一篇博客。最后,怎么也没想到可以用递归的方式求解。。。

根据作者代码思想,做了如下改动:

void PrintListReversingly_Iteratively(ListNode* pHead)
{
    std::stack<int> nodes;

    ListNode* pNode = pHead;
    while(pNode != NULL)
    {
        nodes.push(pNode->m_nValue);
        pNode = pNode->m_pNext;
    }
    
    int value;
    while(!nodes.empty())
    {
        value = nodes.top();
        printf("%d	", value);
        nodes.pop();
    }
}

这里将stack的元素设置为了m_nValue的类型,仔细想想后,认为还是原代码更合理,原因如下:

原代码中,节点地址入栈,因此栈中每个元素所占存储是固定的,在32位操作系统下,指针(地址)占4字节;但如果存储的是节点数据元素,那么每个元素所占存储很可能大于4字节;

void PrintListReversingly_Recursively(ListNode* pHead)
{
    if(pHead == NULL)
    {
        return;
    }
    else
    {
        PrintListReversingly_Recursively(pHead->m_pNext); 
        printf("%d	", pHead->m_nValue);
    }
}
清醒时做事,糊涂时读书,大怒时睡觉,独处时思考; 做一个幸福的人,读书,旅行,努力工作,关心身体和心情,成为最好的自己 -- 共勉
原文地址:https://www.cnblogs.com/hello-yz/p/3240213.html