数据结构算法——链表的各种操作

Posted albert-yzp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构算法——链表的各种操作相关的知识,希望对你有一定的参考价值。

时隔已久,一直没更新博客,感觉很愧疚呀。

先贴上所有的代码。这个是用C++写的

#include "stdafx.h"

//Author:Albert
//Date: 2018.10.28

#include<iostream>
using namespace std;

typedef int datatype;
class Node
{
public:
    int data;
    Node *next;
};

class linkList
{
public:
    linkList();//初始化一个单链表
    ~linkList();//销毁一个单链表
    bool creatLinkListByInput(int n);//通过控制台输入新建一个长度为n的单链表
    void dispLinkList();//把链表里储存的数据都显示出来
    int getLength();
    void insertNodetoEnd(datatype data);
    void insertNode(datatype data, int n);//在第n个数据后插入一个数据data
    void DeleteNode(int n);//删除第n个节点
    void Reverse();
private:
    Node * head;
};

linkList::linkList()
{
    head = new Node;
    head->data = 0;
    head->next = NULL;
}
linkList::~linkList()
{
    delete head;
}
bool linkList::creatLinkListByInput(int n)
{
    Node *pnew, *ptemp;
    ptemp = head;
    if (n < 0) { cout << "error" << endl; return false; }
    for (int i = 0;i < n;i++)
    {
        pnew = new Node;
        cout << "请输入第" << i + 1 << "个值:";
        cin >> pnew->data;
        pnew->next = NULL;
        ptemp->next = pnew;
        ptemp = pnew;
    }
    return true;
}
void linkList::dispLinkList()
{
    Node *p;
    p = head;
    if (p!=NULL)
    {
        while (p->next!=NULL)
        {
            p = p->next;
            cout << p->data << endl;
        }
    }
    else
    {
        cout << "这是一个空链表" << endl;
    }
}

int linkList::getLength()
{
    int n=0;
    Node *p;
    p = head;
    while (p->next!=NULL)
    {
        n++;
        p = p->next;
    }
    return n;
}

void linkList::insertNodetoEnd(datatype data)
{
    Node *pnew=new Node;
    pnew->data = data;
    pnew->next = NULL;

    Node *p=head;
    while (p->next != NULL)
    {
        p = p->next;
    }
    p->next = pnew;
}

void linkList::insertNode(datatype data, int n)
{
    Node *p = head;
    Node *pnew = new Node;
    for (int i = 0;i < n;i++)
    {
        p = p->next;
    }
    //此时p指向的是第n个数据
    pnew->data = data;
    pnew->next = p->next;
    p->next = pnew;
}

void linkList::DeleteNode(int n)
{
    Node *p = head;
    Node *ppre = new Node;
    for (int i = 0;i < n;i++)
    {
        ppre = p;
        p = p->next;
    }
    //ppre是要删除的节点的前一个节点
    ppre->next = p->next;
    delete p;
}

void linkList::Reverse()
{
    
    Node *plast = head->next;
    Node *p = plast->next;
    Node *ptmp = new Node;
    plast->next = NULL;
    while (p->next != NULL)
    {
        ptmp = p;
        p = p->next;
        ptmp->next = plast;
        plast= ptmp;
    }
    p->next = plast;
    head->next = p;
}


int main()
{
    linkList a;

    //新建一个长度为3的单链表
    a.creatLinkListByInput(3);
    a.dispLinkList();
    cout << "链表长度为:" << a.getLength() << endl;


    cout << "在尾部插入一个1:" << endl;
    a.insertNodetoEnd(1);
    a.dispLinkList();
    cout << "链表长度为:" << a.getLength() << endl;


    cout << "在第2个数据后插入1:" << endl;
    a.insertNode(1,2);
    a.dispLinkList();
    cout << "链表长度为:" << a.getLength() << endl;

    cout << "删除第4个数据" << endl;
    a.DeleteNode(4);
    a.dispLinkList();
    cout << "链表长度为:" << a.getLength() << endl;

    cout << "将链表逆置" << endl;
    a.Reverse();
    a.dispLinkList();



    return 0;
}

1、新建一个单链表

bool linkList::creatLinkListByInput(int n)
{
    Node *pnew, *ptemp;
    ptemp = head;
    if (n < 0) { cout << "error" << endl; return false; }
    for (int i = 0;i < n;i++)
    {
        pnew = new Node;
        cout << "请输入第" << i + 1 << "个值:";
        cin >> pnew->data;
        pnew->next = NULL;
        ptemp->next = pnew;
        ptemp = pnew;
    }
    return true;
}

 

这个代码还是我看了别人的之后才写的。在控制台输入一系列数据,返回是否新建成功。

其中最关键的一处就是定义一个head节点。这个节点不储存数据,head->next才是第一个储存的数据。

这样的话就比较好写循环里的内容了,后面的调用也很方便。

用图画一下就很容易理解了。

 技术分享图片

 

显示整个链表数据,得到链表长度什么的,不用多说啦。直接遍历就行。

 

2、插入节点。

void linkList::insertNode(datatype data, int n)
{
Node *p = head;
Node *pnew = new Node;
for (int i = 0;i < n;i++)
{
p = p->next;
}
//此时p指向的是第n个数据
pnew->data = data;
pnew->next = p->next;
p->next = pnew;
}

先遍历到到第n个节点

然后

技术分享图片

3、删除一个节点

void linkList::DeleteNode(int n)
{
    Node *p = head;
    Node *ppre = new Node;
    for (int i = 0;i < n;i++)
    {
        ppre = p;
        p = p->next;
    }
    //ppre是要删除的节点的前一个节点
    ppre->next = p->next;
    delete p;
}

 把它画出来就是

技术分享图片

 

4、单链表的逆置

void linkList::Reverse()
{
    
    Node *plast = head->next;
    Node *p = plast->next;
    Node *ptmp = new Node;
    plast->next = NULL;
    while (p->next != NULL)
    {
        ptmp = p;
        p = p->next;
        ptmp->next = plast;
        plast= ptmp;
    }
    p->next = plast;
    head->next = p;
}

技术分享图片

 

 这里ptmp的作用就是为了防止p->next=plast从而导致无法往下遍历。

我见还有一种用ppre,p,pnex三个指针的。思想跟这个差不多。

感觉自己菜的要死,只能从头再开始学啦。

还有几个问题

链表中环的检测:用的快慢指针的思想。

两个有序链表的合并:遍历,主要是别让指针指乱了。

删除链表倒数第n个节点。如果链表长度知道,就很简单了,转化为整数就好。如果长度不知道,我觉得,就用迭代可以有。

求链表中的中间节点,用快慢针呀。

这几个问题我没时间一个一个的写啦。以后遇到了在一个一个的写。

此外还有循环链表和双向链表,他们都各有千秋,懂的单链表,这都很简单了。

以上是关于数据结构算法——链表的各种操作的主要内容,如果未能解决你的问题,请参考以下文章

python数据结构与算法

循环链表的建立及各种操作

对线性结构------链表的各种操作

JavaScript数据结构与算法 单向链表

链表及其各种函数操作的实现方法

java数据结构与算法:java代码模拟带头节点单向链表的业务