線性表之單鏈表C++實現


源碼:https://github.com/cjy513203427/C_Program_Base/tree/master/54.%E9%93%BE%E8%A1%A8

需要實現的方法

#pragma once
#include"Node.h"
#ifndef LIST_H
#define LIST_H
#include<iostream>
using namespace std;
class List
{
public:
    List();//構造函數
    ~List();//析構函數
    void ClearList();//清空鏈表
    bool ListEmpty();//鏈表判空
    int ListLength();//鏈表長度
    bool GetElem(int i, Node *pNode);//獲取指定索引的元素
    int LocateElem(Node *pNode);//獲取指定元素的索引
    bool PriorElem(Node *pCurrentNode, Node *pPreNode);//獲取前驅結點
    bool NextElem(Node *pCurrentNode, Node *pNextNode);//獲取后繼結點
    void ListTraverse();//遍歷
    bool ListInsert(int i,Node *pNode);//插入元素
    bool ListDelete(int i, Node *pNode);//刪除元素
    bool ListInsertHead(Node *pNode);//插入在頭結點后面
    bool ListInsertTail(Node *pNode);//插入到鏈表最后
private:
    Node * m_pList;
    int m_iLength;
};

#endif // !LIST_H

1.構造函數

堆中為頭結點m_pList申請內存

m_pList數據域置為0

指向地址為空,事實上這里聲明了一個頭結點,頭結點沒有后繼結點並且數據域為空

長度置為0

 

 

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

2.析構函數

調用清空鏈表方法

刪除頭結點並置空

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

3.清空鏈表

聲明一個Node*類型的指針指向m_pList的下一個結點,特別指明:m_pList是頭結點,m_pList->next是頭結點的指針域

判斷currentNode是否為空,即判斷m_pList的指針域是否為空,為空說明currentNode是尾結點,尾結點沒有后繼結點

currentNode不為空時,聲明一個Node*類型的指針temp指向currentNode的下一個結點,也可以理解為temp接收currentNode的指針域值

刪除當前的currentNode,再把temp保存的currentNode的指針域賦值回去

依次類推...

循環結束,再把尾結點指針域置空

 

清空鏈表和析構函數的區別:清空鏈表是將頭結點之后的結點全部清空,析構函數是把頭結點和之后的結點全部清空

void List::ClearList()
{
    Node *currentNode = m_pList->next;
    while (currentNode != NULL)
    {
        Node *temp = currentNode->next;
        delete currentNode;
        currentNode = temp;
    }
    m_pList->next = NULL;
}

4.鏈表判空與獲取長度

沒什么好說的

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

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

5.在頭結點后面插入元素

pNode指針作為參數傳入

temp保存頭結點的指針域,指向第一個結點

在堆中申請一個newNode指針的內存

沒申請到內存返回錯誤

申請到內存,參數的數據域賦值給新結點數據域

頭結點指向新結點

新結點指向原來頭結點的下一個結點,這樣鏈表就連接起來了

 

 

bool List::ListInsertHead(Node *pNode)
{
    Node *temp = m_pList->next;
    Node *newNode = new Node;
    if (newNode == NULL) //判斷申請的結點內存是否為空
    {
        return false;
    }
    else
    {
        newNode->data = pNode->data;
        m_pList->next = newNode;
        newNode->next = temp; 
        m_iLength++;
        return true;
    }
}

6.在尾結點后面插入元素

pNode指針作為參數傳入

currentNode接收頭結點

判斷currentNode是否是尾結點,因為尾結點后繼結點為空

循環到最后一個結點,此時currentNode->next=NULL

在堆中申請一個newNode的內存

沒申請到內存返回錯誤

申請到內存

pNode的數據域賦值給newNode的數據域

新結點指針域置空

currentNode指向新結點

新結點指向空,這樣鏈表就連接起來了,新結點成為了新的尾結點

鏈表長度++

返回正確

 

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

 7.插入元素

判斷參數i的合法性

i不能小於0,i不能大於鏈表長度,i等於鏈表長度代表可以尾元素后插入

currentNode保存頭結點

聲明newNode

pNode數據域賦值給newNode數據域

新結點指向原來結點的下一個結點

原來的結點指向新結點

 

bool List::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;
    }
    else
    {
        newNode->data = pNode->data;
        newNode->next = currentNode->next;
        currentNode->next = newNode;
        return true;
    }
}

8.刪除元素

判斷i是否合法,索引最大是m_iLength-1,和循環條件k<i對應

currentNode保存頭指針

currentNodeBefore置空

currentNodeBefore指向currentNode的下一個結點的指針域,這樣currentNode就可以被刪除釋放了

pNode數據域接收當前結點的數據域

刪除當前結點並置空

 

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

 9.獲取指定索引的元素

邏輯同刪除元素

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

10.獲取指定元素的索引

currenNode保存頭指針

只要currentNode的指針域/指向不為空,繼續下去

如果參數的數據域等於currentNode的數據域,返回count,count就是索引

int List::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;
}

11.獲取前驅結點

currentNode保存頭結點

中間變量tempNode置空

currentNode指針域不為空開始循環

tempNode保存當前結點

currentNode像后移一位

如果pCurrentNode的數據域等於當前結點的數據域

如果tempNode等於頭結點,返回錯誤

將tempNode的數據域賦值給pPreNode的數據域,此時tempNode是保存的currentNode,currentNode是下一個的結點

所以currentNode->data==pCurrentNode->data是currentNode下一個結點的數據域和pCurrentNode比較

bool List::PriorElem(Node *pCurrentNode, Node *pPreNode)
{
    Node *currentNode = m_pList;
    Node *tempNode = NULL;
    int count = 0;
    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;
}

12.獲取后繼結點

currentNode保存頭指針

currentNode指針域不為空執行循環

currentNode一直向后移動

如果pCurrentNode的數據域等於currentNode的數據域

如果是尾結點,返回錯誤

再將當前結點指向的下一個結點的數據域賦值給pNextNode的數據域

bool List::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;
        }
    }
}

13.遍歷

currentNode保存頭指針

currentNode只要不是尾結點一直遍歷下去

currentNode后移,調用printNode()方法

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM