面试基础_02单向链表操作

直接上代码,在操作的过程中需要注意的是:在对节点操作过程中,对第一个节点和其他位置的节点操作方式不一样。

目前包含以下几种面试经常会碰到的函数:

    void reverseList();                     //节点的倒置
    NODE* reverseGet(int pos);              //获取倒数第几个数据
    NODE* getMidNode();                     //获取中间的节点
    NODE* hasCircle();                      //检查一个链表里面有没有环


实现代码如下:

头文件

/************************************************************************* 
    > File Name: testlist.h
    > Author: qiaozp 
    > Mail: qiaozongpeng@163.com 
    > Created Time: 2014-9-25 10:00:36
    > Attention: 本段代码中第几个位置 默认是从1开始算的 而非0
 ************************************************************************/ 

//链表中的节点
typedef struct _NODE
{
    char name[100];
    int age;
    struct _NODE* next;
    void clear()
    {
        memset(name, 0, 100);
        age = 0;
        next = NULL;
    }

    _NODE()
    {
        clear();
    }
}NODE;

//链表的操作类
class LIST
{
public:
    LIST();
    ~LIST();

    void clear();                           //清空操作
    int getCnt();                           //获取当前链表个数
    void insetNode(NODE& inNode);           //在尾部插入节点
    void insetNode(int pos, NODE& inNode);  //在某一个位置插入节点
    void show();                            //展示链表中的数据
    void deleteNode(int pos);               //删除节点
    void reverseList();                     //节点的倒置
    NODE* reverseGet(int pos);              //获取倒数第几个数据
    NODE* getMidNode();                     //获取中间的节点
    NODE* hasCircle();                      //检查一个链表里面有没有环

private:
    NODE* node;
    int iCnt;
};



CPP文件

/************************************************************************* 
> File Name: testlist.c 
> Author: qiaozp 
> Mail: qiaozongpeng@163.com 
> Created Time: 2014-9-25 10:00:36
> Attention: 本段代码中第几个位置 默认是从1开始算的 而非0
************************************************************************/ 
#include <string.h>
#include <iostream>
#include "testlist.h"
using namespace std;


LIST::LIST():node(NULL), iCnt(0)
{
}

LIST::~LIST()
{
    NODE* pNode;
    while (this->node != NULL)
    {
        pNode = node->next;
        delete node;
        node = pNode;
    }
}

void LIST::clear()
{
    NODE* pNode;
    while (this->node != NULL)
    {
        pNode = node->next;
        delete node;
        node = pNode;
    }
}

int LIST::getCnt()
{
    return iCnt;
}

void LIST::insetNode(NODE& inNode)
{
    NODE* pNode = node;
    //为空的情况下,直接插入
    if(node == NULL)
    {
        node = new NODE();
        node->age = inNode.age;
        strncpy(node->name, inNode.name, strlen(inNode.name));
        node->next = NULL;
    }
    else
    {
        //非空的情况下,找到最后一个位置插入
        NODE* newNode = new NODE();
        newNode->age = inNode.age;
        strncpy(newNode->name, inNode.name, strlen(inNode.name));
        while (pNode->next != NULL)
        {
            pNode = pNode->next;
        }
        newNode->next = NULL;
        pNode->next = newNode;
    }
    ++iCnt;
}

void LIST::insetNode(int pos, NODE& inNode)
{
    if (getCnt() == 0)
    {
        cout << "空链表" << endl;
        return ;
    }

    if ((pos < 0) || (pos > getCnt()))
    {
        cout << "插入的位置不对" << endl;
        return ;
    }

    NODE* pNode = node;
    NODE* newNode = NULL;
    newNode = new NODE();
    newNode->age = inNode.age;
    strncpy(newNode->name, inNode.name, strlen(inNode.name));
    //没有前驱数据的下的操作
    if ((node == NULL) || (pos == 1))
    {
        newNode->next = node;
        node = newNode;
    }
    else
    {
        //有前驱数据情况下的操作
        while ((--pos) > 1)
        {
            pNode = pNode->next;
        }
        newNode->next = pNode->next;
        pNode->next = newNode;
    }
    ++iCnt;
}

void LIST::show()
{
    NODE* pNode = node;
    while (pNode != NULL)
    {
        cout << pNode->name << " : " << pNode->age << endl;
        pNode = pNode->next;
    }
}
void LIST::deleteNode(int pos)
{
    if((pos < 0) || (pos > getCnt()))
    {
        cout << "超出选择范围" << endl;
        return ;
    }

    if(this->getCnt() == 1)
    {
        //只有一个节点的话直接删除
        delete node;
        node = NULL;
        --iCnt;
    }
    else
    {
        //有多个节点的情况下需要保存删除节点中的数据
        NODE* pNode = node;
        while((--pos) > 1)
        {
            pNode = pNode->next;
        }
        NODE* tmp = pNode->next;
        pNode->next = pNode->next->next;
        delete tmp;
        --iCnt;
    }
}

void LIST::reverseList()
{
    if (this->getCnt() == 0)
    {
        return ;
    }

    //A-->B-->C--D  ==> A<--B<--C<--D
    //就是指向的转变
    //以当前节点为基础,找到下面一个节点,转换指针,然后往后移
    NODE* pre = NULL;
    NODE* next = NULL;
    while(node != NULL)
    {
        next = node->next;
        node->next = pre;
        pre = node;
        node = next;
    }
    node = pre;
}

NODE* LIST::getMidNode()
{
    //reverseGet()函数机制类似
    //两个指针,一个一次走两步,一个一次走一步,走两步的到尾了,走一步的正好到中间
    if (node == NULL)
    {
        cout << "链表是空的,取毛啊." << endl;
        return NULL;
    }

    NODE* fast = node;
    NODE* slow = node;
    while((fast != NULL) && (fast->next != NULL))
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    
    return slow;
}

NODE* LIST::reverseGet(int pos)
{
    if ((pos > iCnt) || (pos < 0))
    {
        cout << "获取的数据超过最大限制" << endl;
        return NULL;
    }

    //获取倒数第几个数据
    //方法:定义两个变量fasrt slow同时指向头,
    //然后fast先走pos步,然后一起走,当fast到尾的时候,slow就是倒数第pos个
    NODE* fast;
    NODE* slow;
    fast = slow = node;
    int tmp = pos;
    for (; tmp > 0 && fast != NULL; --tmp)
    {
        fast = fast->next;
    }

    while (fast != NULL)
    {
        slow = slow->next;
        fast = fast->next;
    }

    return slow;
}

NODE* LIST::hasCircle()
{
    //原理和getMidNode reverseGet 差不多,利用两个节点产生距离查找交集
    NODE* fast = node;
    NODE* slow = node;
    while ((fast != NULL) && (fast->next != NULL))
    {
        fast = fast->next->next;
        slow = slow->next;
        if (fast == slow)
        {
            return fast;
        }
    }
    return NULL;
}



int main()
{
    LIST l;
    NODE node;

    strcat(node.name, "MJ");
    node.age = 12;
    l.insetNode(node);

    node.clear();
    strcat(node.name, "qiaozp");
    node.age = 13;
    l.insetNode(node);

    node.clear();
    strcat(node.name, "zhuh");
    node.age = 15;
    l.insetNode(2, node);

    node.clear();
    strcat(node.name, "Json");
    node.age = 16;
    l.insetNode(1, node);

    cout << "倒置之前的数据 : " << endl;
    l.show();
    l.reverseList();
    cout << "倒置之后的数据 : " << endl;
    l.show();

    cout << "删除第三个节点后的数据 : " << endl;
    l.deleteNode(3);
    l.show();

    NODE* rNode = l.reverseGet(2);
    if (rNode == NULL)
    {
        return -1;
    }
    cout << "获取的倒数第二个数据为: 名字: " << rNode->name << ". 年龄:" << rNode->age << endl;


    rNode = NULL;
    rNode = l.getMidNode();
    if (rNode == NULL)
    {
        return -1;
    }
    cout << "获取到的中间的数据为: 名字: " << rNode->name << ". 年龄:" << rNode->age << endl;


    //倒转数据之后进行打印
    return 0;

}





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值