数据结构和算法分析Java-Python-Django社区程序员

【慕课-数据结构-C++语言】线性表篇

2018-04-23  本文已影响55人  苍云横渡

原文地址:https://www.cloudcrossing.xyz/post/30/

线性表是n个数据元素的有限序列。可应用与通讯录、一元多项式等等。

顺序表

新建List.h和List.cpp

#List.h
#ifndef LIST_H
#define LIST_H

class List
{
public:
    List(int size);     //创建线性表
    ~List();            //销毁线性表
    void CleanList();   //清空线性表
    bool ListEmpty();   //判断线性表是否为空
    bool ListFull();    //判断线性表是否为满
    int ListLength();   //获取线性表长度(元素个数)
    bool GetElem(int i, int *e);    //获取指定元素
    int LocateElem(int *e);         //寻找第一个满足e的数据元素的位序
    bool PriorElem(int *currentElem, int *preElem);     //获取指定元素的前驱
    bool NextElem(int *currentElem, int *nextElem);     //获取指定元素的后继
    bool ListInsert(int i, int *e);     //在第i个位置插入元素
    bool ListDelete(int i, int *e);     //删除第i个位置的元素
    void ListTraverse();                //遍历线性表
public:
    int *m_pList;
    int m_iSize;
    int m_iLength;
};

#endif // LIST_H
#List.cpp
#include "stdafx.h"
#include "List.h"
#include "iostream"

using namespace std;

List::List(int size)
{
    m_iSize = size;
    m_pList = new int[m_iSize];
    m_iLength = 0;
}


List::~List()
{
    delete[]m_pList;
    m_pList = NULL;
}

void List::CleanList()
{
    m_iLength = 0;
}

bool List::ListEmpty()
{
    return m_iLength == 0 ? true : false;
}

int List::ListLength()
{
    return m_iLength;
}

bool List::GetElem(int i, int *e)
{
    if (i < 0 || i >= m_iSize)
    {
        return false;
    }
    *e = m_pList[i];
    return true;
}

int List::LocateElem(int *e)
{
    for (int i = 0; i < m_iLength; i++)
    {
        if (m_pList[i] == *e)
        {
            return i;
        }
    }
    return -1;
}

bool List::PriorElem(int *currentElem, int *preElem)
{
    int temp = LocateElem(currentElem);
    if (temp == -1)
    {
        return false;
    }
    else
    {
        if (temp == 0)
        {
            return false;
        }
        else
        {
            *preElem = m_pList[temp - 1];
            return true;
        }
    }
}

bool List::NextElem(int *currentElem, int *nextElem)
{
    int temp = LocateElem(currentElem);
    if (temp == -1)
    {
        return false;
    }
    else
    {
        if (temp == m_iLength - 1)
        {
            return false;
        }
        else
        {
            *nextElem = m_pList[temp + 1];
            return true;
        }
    }
}

void List::ListTraverse()
{
    for (int i = 0; i < m_iLength; i++)
    {
        cout << m_pList[i] << endl;
    }
}

bool List::ListInsert(int i, int *e)
{
    if (ListFull())
    {
        cout << "栈满,插入失败" << endl;
        return false;
    }
    if (i < 0 || i > m_iLength)
    {
        return false;
    }
    for (int k = m_iLength - 1; k >= i; k--)
    {
        m_pList[k + 1] = m_pList[k];
    }
    m_pList[i] = *e;
    m_iLength++;
    return true;
}

bool List::ListDelete(int i, int *e)
{
    if (ListEmpty())
    {
        cout << "栈空,删除失败" << endl;
        return false;
    }
    if (i < 0 || i >= m_iLength)
    {
        return false;
    }
    *e = m_pList[i];
    for (int k = i + 1; k < m_iLength; k++)
    {
        m_pList[k - 1] = m_pList[k];
    }
    m_iLength--;
    return true;
}

测试用例demo.cpp

#demo.cpp
#include "stdafx.h"
#include "List.h"
#include "iostream"

using namespace std;

int main(void)
{
    int e1 = 3;
    int e2 = 5;
    int e3 = 7;
    int e4 = 2;
    int e5 = 9;
    int e6 = 1;
    int e7 = 8;
    int temp = 0;

    List * list1 = new List(7);
    cout << "before length:" << list1->ListLength() << endl;

    list1->ListDelete(0, &temp);
    list1->ListInsert(0, &e1);
    list1->ListInsert(1, &e2);
    list1->ListInsert(2, &e3);
    list1->ListInsert(3, &e4);
    list1->ListInsert(4, &e5);
    list1->ListInsert(5, &e6);
    list1->ListInsert(6, &e7);
    list1->ListInsert(6, &e7);
    cout << "after length:" << list1->ListLength() << endl;

    list1->ListTraverse();

    list1->GetElem(0, &temp);
    cout << "[0] is:" << temp << endl;

    temp = 5;
    cout << "where 5 in " << list1->LocateElem(&temp) << endl;

    list1->NextElem(&e4, &temp);
    cout << "4 next is: " << temp << endl;
    list1->PriorElem(&e4, &temp);
    cout << "4 prior is: " << temp << endl;

    list1->ListDelete(0, &temp);

    if (!list1->ListEmpty())
    {
        cout << "not empty" << endl;
    }

    list1->CleanList();

    if (list1->ListEmpty())
    {
        cout << "empty" << endl;
    }

    delete list1;

    system("pause");
    return 0;
}

运行结果:


单链表

首先新建节点类 Node.h 和 Node.cpp。

#Node.h
#ifndef NODE_H
#define NODE_H

class Node
{
public:
    int data;    //数据域
    Node *next;  //指针域,指向Node类的指针变量
    void printNode();
};

#endif // NODE_H

PS:class 默认访问修饰符是 private 而不是 public,所以在这里为了能访问类的元素,把数据和指针域放到了 public 下。.

#Node.cpp
#include "Node.h"
#include "iostream"
#include "stdafx.h"

using namespace std;

void Node::printNode()
{
    cout << data << endl ;
}

接着新建单链表类 List_one.h 和 List.cpp

#List_one.h
#ifndef LIST_ONE_H
#define LIST_ONE_H

#include "Node.h"

class List_one
{
public:
    List_one();     //创建链表
    ~List_one();            //销毁链表
    void CleanList();       //清空链表
    bool ListEmpty();       //判断链表是否为空
    int ListLength();       //获取链表长度(元素个数)
    bool GetElem(int i, Node *pNode);    //获取指定元素
    int LocateElem(Node *pNode);         //寻找第一个满足e的数据元素的位序
    bool PriorElem(Node *pCurrentNode, Node *pPreNode);     //获取指定元素的前驱
    bool NextElem(Node *pCurrentNode, Node *pNextNode);     //获取指定元素的后继
    bool ListInsert(int i, Node *pNode);     //在第i个位置插入元素
    bool ListDelete(int i, Node *pNode);     //删除第i个位置的元素
    void ListTraverse();                 //遍历线性表
    bool ListInsertHead(Node *pNode);        //在链表头插入元素
    bool ListInsertTail(Node *pNode);        //在链表头插入元素
public:
    Node *m_pList;
    int m_iLength;
};

#endif // LIST_ONE_H
#List_one.cpp
#include "List_one.h"
#include "stdafx.h"
#include "iostream"

using namespace std;

List_one::List_one()
{
    m_pList = new Node;
    m_pList->data = 0;
    m_pList->next = NULL;
    m_iLength = 0;
}

List_one::~List_one()
{
    CleanList();
    delete m_pList;
    m_pList = NULL;
}

void List_one::CleanList()
{
    Node *currentNode = m_pList->next;
    while (currentNode != NULL)
    {
        Node *temp = currentNode->next;
        delete currentNode;
        currentNode = temp;
    }
    m_pList->next = NULL;
    m_iLength = 0;
}

bool List_one::ListEmpty()
{
    return m_iLength == 0 ? true : false;
}

int List_one::ListLength()
{
    return m_iLength;
}

bool List_one::GetElem(int i, Node *pNode)
{
    if (i < 0 || i >= m_iLength)
    {
        return false;
    }
    Node *currentNode = m_pList;
    for (int k = 0; k <= i; k++)
    {
        currentNode = currentNode->next; 
    }
    pNode->data = currentNode->data;
    return true;
}

int List_one::LocateElem(Node *pNode)
{
    Node *currentNode = m_pList;
    int count = 0;
    while (currentNode->next != NULL)
    {
        currentNode = currentNode->next;
        if (currentNode->data == pNode->data)
        {
            return count;
        }
        count++;
    }
    return -1;
}

bool List_one::PriorElem(Node *pCurrentNode, Node *pPreNode)
{
    Node *currentNode = m_pList;
    Node *tempNode = NULL;
    while (currentNode->next != NULL)
    {
        tempNode = currentNode;
        currentNode = currentNode->next;
        if (currentNode->data == pCurrentNode->data)
        {
            if (tempNode == m_pList) //判断是否为第一个节点
            {
                return false;
            }
            pPreNode->data = tempNode->data;
            return true;
        }
    }
    return false;
}

bool List_one::NextElem(Node *pCurrentNode, Node *pNextNode)
{
    Node *currentNode = m_pList;
    while (currentNode->next != NULL)
    {
        currentNode = currentNode->next;
        if (currentNode->data == pCurrentNode->data)
        {
            if (currentNode->next == NULL) //判断是否为最后一个节点
            {
                return false;
            }
            pNextNode->data = currentNode->next->data;
            return true;
        }
    }
    return false;
}

void List_one::ListTraverse()
{
    Node *currentNode = m_pList;
    while (currentNode->next != NULL)
    {
        currentNode = currentNode->next;
        currentNode->printNode();
    }
}

bool List_one::ListInsert(int i, Node *pNode)
{
    if (i < 0 || i > m_iLength)
    {
        return false;
    }
    Node *currentNode = m_pList;
    for (int k = 0; k < i; k++)
    {
        currentNode = currentNode->next;
    }
    Node *newNode = new Node;
    if (newNode == NULL)
    {
        return false;
    }
    newNode->data = pNode->data;
    newNode->next = currentNode->next;
    currentNode->next = newNode;
    return true;
}

bool List_one::ListDelete(int i, Node *pNode)
{
    if (ListEmpty())
    {
        cout << "链空,删除失败" << endl;
        return false;
    }
    if (i < 0 || i >= m_iLength)
    {
        return false;
    }
    Node *currentNode = m_pList;    //保存头节点
    Node *currentNodeBefore = NULL; //头节点前一个节点不存在,为NULL
    for (int k = 0; k < i; k++)    //查找第i个节点  
    {
        currentNodeBefore = currentNode;  //找到第i-1个节点
        currentNode = currentNode->next;  //循环结束代表currentNode就是第i节点  
    }
    currentNodeBefore->next = currentNode->next; // 第i个节点指针域赋给第i - 1节点指针域
    pNode->data = currentNode->data;     //删掉节点的数据域赋给pNode输出  
    delete currentNode;          //释放删除节点的内存
    currentNode = NULL;
    m_iLength--;
    return true;
}

bool List_one::ListInsertHead(Node *pNode)
{
    Node *newNode = new Node;
    if (newNode == NULL)
    {
        return false;
    }
    newNode->data = pNode->data;
    newNode->next = m_pList->next;
    m_pList->next = newNode;
    m_iLength++;
    return true;
}

bool List_one::ListInsertTail(Node *pNode)
{
    Node *currentNode = m_pList;
    while (currentNode->next != NULL)
    {
        currentNode = currentNode->next;
    }
    Node *newNode = new Node;
    if (newNode == NULL)
    {
        return false;
    }
    newNode->data = pNode->data;
    newNode->next = NULL;
    currentNode->next = newNode;
    m_iLength++;
    return true;
}

首先构造函数实质上就是创建链表的头结点,所以其数据域data赋值为0,指针域next赋值为NULL,当然,长度m_iLength也应赋值为0。

接着析构函数先放放,这里先讲清空链表的函数void CleanList()。首先先创建一个节点类指针currentNode并赋值为头结点的next;然后利用while循环释放每一个节点,直到currentNode指向NULL。最后将头结点的next也指向NULL,初始化链表长度。在循环里边,先创建一个节点类指针temp,用来存放currentNode->next,为了在后面释放currentNode时(也就是当前循环的节点)能把currentNode->next赋值给currentNode(保证不断链)。

讲完清空链表函数来说说析构函数,因为析构函数实质就是释放链表所有元素,包括头结点,所以我们可以利用利用清空链表函数先把链表清空,接着释放头结点,并将头结点指向NULL,done。

判空和获取长度类似,略。

接着讲讲GetElem(int i, Node *pNode)获取指定元素的函数。首先传入的参数有两个,位序和存放(也就是取来要存放的变量)。在寻找元素之前,需要先判断位序是否合法;然后按照惯例,创建一个节点类指针currentNode存放头结点;然后利用for循环找到链表的第i个元素赋值给currentNode;最后将currentNode->data赋值给参数pNode->data

int LocateElem(Node *pNode)寻找第一个满足pNode的数据元素的位序的函数。因为找的是位序,所以函数返回的类型为int。首先创建一个节点类指针currentNode存放头结点,并创建一个 int count=0 用来表示当前元素(头结点)的位序;然后利用while进行遍历,在每一次循环里边进行判断 currentNode->data == pNode->data 是否成立,如果成立返回当前count,如果不成立,count++进入下一次循环;最后也没找到的话,返回-1.

bool PriorElem(Node *pCurrentNode, Node *pPreNode)获取指定元素的前驱函数,传入的参数有两个,一个是指定的节点,一个是存放节点。和前边两个函数类似,首先创建一个节点类指针赋值为头结点,还需创建一个临时节点类指针tempNode指向NULL,然后利用while循环遍历链表。在每一次循环中,先将当前节点currentNode赋值给临时节点,将currentNode->next赋值给当前节点currentNode,然后判断currentNode(其实是当前节点的next)的数据域是否和指定节点的相等。如果相等时继续判断临时节点(即当前节点)是否为头结点,如果不是头结点,则当前节点为指定节点的前驱。

bool NextElem(Node *pCurrentNode, Node *pNextNode)获取指定元素的后继和获取前驱类似,这里不再需要创建临时节点。在遍历的每一次循环中,先进行节点的移动(从前一节点移动到当前节点),然后直接将判断当前节点的数据域是否和指定节点的相等。如果相等,继续判断当前节点next的指针域是否指向NULL(即判断指定**节点是否为最后一个节点)。如果不是,则将当前节点的 next 的数据域(即当前节点的后继数据域)取出。

void ListTraverse()遍历线性表,略。

接着来讲bool ListInsertHead(Node *pNode)在链表头插入元素。首先创建一个节点类指针newNode,将要插入节点的数据域赋值给newNode->data,然后将newNode->next = m_pList->next,最后将头结点的指针域指向newNode,不要忘记m_iLength++

bool ListInsertTail(Node *pNode)在链表头插入元素。首先创建一个节点类指针currentNode指向头节点,接着遍历到链表尾指针,然后创建一个节点类指针newNode,将要插入节点的数据域赋值给newNode->data,然后将newNode->next 指向NULL,最后将链表尾的指针域指向newNode,m_iLength++

bool ListInsert(int i, Node *pNode)在第 i 个位置插入元素。和上边两个函数类x似,不同的是需要先判断插入的位置合不合法。之后创建一个节点类指针currentNode指向头节点,然后遍历到插入位置的前一个节点。接着创建一个节点类newNode,将要插入节点的数据域赋值给newNode->data,然后将newNode->next 指向currentNode->next(要插入的位置的节点),最后将currentNode->next(插入位置的前一个节点的指针域)指向newNode,m_iLength++

最后讲bool ListDelete(int i, Node *pNode)删除第 i 个位置的元素。首先需要判空以及判断删除位置是否合法,接着创建两个节点类,currentNode指向头节点,currentNodeBefore指向NULL。然后遍历到第 i 个节点(要删除的节点)时,currentNodeBefore为第 i-1 个节点,currentNode为第 i 个节点。接着将第 i 个节点指针域赋给第 i-1 节点指针域(即跳过了第 i 个节点),把第 i 节点的数据域赋给pNode输出,释放删除节点的内存,m_iLength--

【注意】在插入操作中,不能直接对pNode进行链接操作,而不用新建newNode节点。直接将传入的结点作为链表中新添加的结点内存,是不安全的。因为传入的结点内存是有可能在链表外被释放掉的,如果被释放掉,则链表就会断开失效;而申请一个新的结点内存作为链表的结点内存,则该内存只有在链表中才可以被释放掉,这样保证了链表内存是安全释放的。

运行一个例子看看

#demo_one.cpp
#include "stdafx.h"
#include "iostream"
#include "List_one.h"
#include "Node.h"

using namespace std;

int main(void)
{
    Node node1; node1.data = 3;
    Node node2; node2.data = 4;
    Node node3; node3.data = 5;
    Node node4; node4.data = 6;
    //Node node5; node5.data = 7;
    Node temp;  temp.data = 0;
    List_one *pList = new List_one;

    /*pList->ListInsertHead(&node1);
    pList->ListInsertHead(&node2);
    pList->ListInsertHead(&node3);
    pList->ListInsertHead(&node4);*/
    pList->ListInsertTail(&node1);
    pList->ListInsertTail(&node2);
    pList->ListInsertTail(&node3);
    pList->ListInsertTail(&node4);
    //pList->ListInsert(1, &node5);

    pList->ListDelete(2, &temp);
    //pList->NextElem(&node1, &temp);
    cout << "temp:" << temp.data << endl;

    pList->ListTraverse();

    delete pList;
    pList = NULL;

    system("pause");
    return 0;
}

运行结果:


顺序表的应用以及单链表的应用的代码我上传到了github

上一篇 下一篇

猜你喜欢

热点阅读