C++:单链表、双向链表、STL中的list容器

目录

单链表

双向链表

STL中的list


  • 单链表


  • 单链表的结构

  • 头文件(List.h)

/*数据结构:单链表*/

#ifndef LIST_H
#define LIST_H

#include <iostream>

using namespace std;
typedef int ElementType;//定义数据类型
class Node{//定义链表节点
public:
    Node(){next=NULL;}
    ElementType data;
    Node* next;
};

class List{
public:
    /*构造函数*/
    List();
    /*析构函数*/
    ~List();


    /*修改链表的方法*/
    void insert_head(ElementType data);//将data插入到链表头部
    void insert_tail(ElementType data);//将data插入到链表尾部
    bool insert_next(Node* node,ElementType data);//将data插入到node结点后
    bool delete_next(Node* node);//删除node结点后的节点
    void reverse();//逆置

    /*检索链表的方法*/
    Node* Search(ElementType data);//查找数据为data的结点
    Node* Find(int ith);//返回列表中第ith个结点,其中头节点记为第0结点

    /*获取链表基本信息的方法*/
    int list_size(){return size;}
    Node* head(){return pHead;}
    Node* tail(){return pTail;}

    /*其他*/
    void display();//从头到尾输出链表
private:
    size_t size;
    Node* pHead;//头结点指针
    Node* pTail;//指向链表尾部结点的指针
};

#endif // LIST_H
  • 源文件(List.cpp)

/*数据结构:单链表*/

#include "List.h"
/*****************************************************************
Function:List
Description:
            构造函数,主要是初始化size、实例化头结点、初始化
            头指针pHead和尾指针pTail。
*****************************************************************/
List::List(){
    size = 0;
    pHead = new Node();
    pTail = pHead;
}

/*****************************************************************
Function:~List
Description:析构函数,主要是释放链表的空间。
*****************************************************************/
List::~List(){
    //不断的删除头节点后面的节点,直至size=0
    while(size>0)
        delete_next(pHead);
    delete pHead;
}

/*****************************************************************
Function:insert_head
Description:将数据data插入到链表的头部。
*****************************************************************/
void List::insert_head(ElementType data){
    //申请空间存储data
    Node* node = new Node();
    node->data = data;
    //当为空链表时,插入头部的同时还有移动尾部指针
    if(size==0)
        pTail = node;
    node->next = pHead->next;
    pHead->next = node;
    size++;
}

/*****************************************************************
Function:insert_head
Description:将数据data插入到链表的尾部。
*****************************************************************/
void List::insert_tail(ElementType data){
    Node* node = new Node();
    node->data = data;

    pTail->next = node;
    pTail = pTail->next;
    size++;
}

/*****************************************************************
Function:insert_next
Description:将数据data插入到结点node之后。
*****************************************************************/
bool List::insert_next(Node* node,ElementType data){
    if(node==NULL)
        return false;
    Node* p = new Node();
    p->data = data;

    p->next = node->next;
    node->next = p;
    //当插入的节点为尾部时,需要移动尾部指针pTail
    if(node==pTail)
        pTail = p;
    size++;
    return true;
}

/*****************************************************************
Function:delete_next
Description:将结点node之后的节点删除。
*****************************************************************/
bool List::delete_next(Node* node){
    if(NULL==node||NULL==node->next)
        return false;
    Node* p = node->next;
    node->next = node->next->next;
    delete p;
    size--;
    return true;
}
/*****************************************************************
Function:reverse
Description:反转链表。
*****************************************************************/
void List::reverse(){
    if(size<2)
        return;
    //pre是p的前序结点,p是post的前序结点
    Node* pre = pHead->next;
    Node* p = pre->next;
    Node* post = NULL;
    //处理尾部结点
    pTail = pre;
    pTail->next = NULL;
    while(p!=NULL){
        post = p->next;
        p->next = pre;
        pre = p;
        p = post;
    }
    //处理头结点
    pHead->next = pre;
}

/*****************************************************************
Function:Search
Description:查找数据为data的节点。
*****************************************************************/
Node* List::Search(ElementType data){
    if(size>0){
        Node* p = pHead->next;
        while(p!=NULL){
            if(p->data==data)
                return p;
            p = p->next;
        }
    }
    return NULL;
}

/*****************************************************************
Function:Find
Description:返回列表中第ith个节点,其中头节点记为第0节点。
*****************************************************************/
Node* List::Find(int ith){
    if(ith<0||ith>size)
        return NULL;
    Node* p = pHead;
    for(int i=0;i<ith;i++)
        p = p->next;
    return p;
}

void List::display(){
    Node* p = pHead->next;
    while(p!=NULL){
        cout<<p->data<<" ";
        p = p->next;
    }
    cout<<endl;
}
  • 测试
#include <iostream>
#include "List.h"

using namespace std;

int main()
{
    List* list = new List();
    list->insert_tail(4);
    list->insert_head(3);
    list->insert_head(2);
    list->insert_head(1);
    list->insert_next(list->tail(),5);//1,2,3,4,5
    list->display();
    list->delete_next(list->Search(3));//1,2,3,5
    list->display();
    list->reverse();//5,3,2,1
    list->display();
    delete list;//µ÷ÓÃÎö¹¹º¯Êý
    return 0;
}
  • 注意事项

        1.在头结点后插入(insert_head)

            正常的插入操作

            特殊情况:当列表为空时,除了普通的插入操作,还需要移动pTail.

        2.在指定结点后插入(insert_next)

            类似问题(1)如果插入的位置是pTail时,需要移动pTial。

        3.反转链表(reverse)

            需要三个指针pre、p、post,反转后p会指向pre,此时会丢掉原来p之后的结点,因此需要使用post进行记录。


  • 双向链表


  • 双向链表的结构

  • 头文件(DList.h)

/*数据结构:双向链表*/

#ifndef DLIST_H
#define DLIST_H

#include <iostream>
using namespace std;
typedef int ElementType;

class DNode{
public:
    DNode(){
        prev = NULL;
        next = NULL;
    }

    ElementType data;
    DNode* prev;
    DNode* next;
};

class DList{
public:
    DList();
    ~DList();

    /*插入、删除*/
    void insert_next(DNode* node,ElementType data);//在结点node后插入数据data
    void insert_prev(DNode* node,ElementType data);//在结点node前插入数据data
    bool remove(DNode* node);//删除node结点

    /*查找*/
    DNode* Search(ElementType data);//查找链表中数据为data的结点
    DNode* Find(int ith);//查找链表中第ith个结点

    /*链表信息*/
    int list_size(){return size;}
    DNode* head(){return pHead;}
    DNode* tail(){return pTail;}

    /*其他*/
    void display();
private:
    size_t size;
    DNode* pHead;
    DNode* pTail;
};
#endif // DLIST
  • 源文件(DList.cpp)

/*数据结构:双向链表*/

#include "DList.h"

/*****************************************************************
Function:DList
Description:
            构造函数,主要是初始化size、实例化头结点、初始化
            头指针pHead和尾指针pTail。
*****************************************************************/
DList::DList(){
    size = 0;
    pHead = new DNode();
    pTail = pHead;
}
/*****************************************************************
Function:~DList
Description:析构函数,主要是释放链表的空间。
*****************************************************************/
DList::~DList(){
    while(size>0)
        remove(pTail);
    delete pHead;
}
/*****************************************************************
Function:insert_next
Description:在node结点后插入数据data。
*****************************************************************/
void DList::insert_next(DNode* node,ElementType data){
    if(NULL==node)
        return;
    DNode* p = new DNode();
    p->data = data;

    if(node->next!=NULL){//如果node不是末尾的结点
        //处理p与node->next的关系
        p->next = node->next;
        node->next->prev = p;
    }
    //处理p与node的关系
    node->next = p;
    p->prev = node;
    //如果node是pTail,那么就修改pTail
    if(node==pTail)
        pTail = node->next;
    size++;
}
/*****************************************************************
Function:insert_prev
Description:将数据data插入到结点node之前。
*****************************************************************/
void DList::insert_prev(DNode* node,ElementType data){
    //node为空或者在pHead前插入结点是不允许的
    if(node==NULL||node==pHead)
        return;
    DNode* prev = node->prev;
    this->insert_next(prev,data);
}
/*****************************************************************
Function:remove
Description:从链表中删除node结点。
*****************************************************************/
bool DList::remove(DNode* node){
    if(NULL==node)
        return false;
    DNode* prev = node->prev;
    if(node==pTail){
        //如果node是末尾结点,直接修改前序结点,并且要修改pTail
        prev->next = NULL;
        pTail = prev;
    }
    else{
        prev->next = node->next;
        node->next->prev = prev;
    }
    delete node;
    size--;
    return true;
}
/*****************************************************************
Function:Search
Description:查找链表中数据为data的结点。
*****************************************************************/
DNode* DList::Search(ElementType data){
    DNode* p = pHead->next;
    while(p!=NULL){
        if(p->data==data)
            return p;
        p = p->next;
    }
}
/*****************************************************************
Function:Find
Description:查找链表中第ith个结点。
*****************************************************************/
DNode* DList::Find(int ith){
    if(ith>size||ith<1)
        return NULL;
    DNode* p = pHead;
    for(int i=0;i<ith;i++)
        p = p->next;
    return p;
}

void DList::display(){
    DNode* p = pHead->next;
    while(p!=NULL){
        cout<<p->data<<" ";
        p = p->next;
    }
    cout<<endl;
}
  • 测试

/*数据结构:双向链表*/
#include <iostream>
#include "DList.h"
using namespace std;

int main()
{
    DList* l = new DList();
    for(int i=0;i<3;i++)
        l->insert_next(l->head(),3-i);
    l->display();//1,2,3
    l->insert_prev(l->tail(),4);
    l->display();//1,2,4,3
    l->remove(l->Search(4));
    l->display();//1,2,3
    delete l;
    return 0;
}
  • 注意事项

        1.插入方法

        2.删除方法

        3.不论是插入还是删除,要注意处理pTail这种特殊情况。


  • STL中的list



/*STL中的List*/

#include <iostream>
#include <list>
using namespace std;

int main(){
    /*构造函数*/
    list<int> L0;//空list
    list<int> L1(9);//包含9个0的list
    list<int> L2(8,3);//包含8个3的list
    list<int> L3(L2);//复制L2到L3
    list<int> L4(L2.begin(),L2.end());//从L2.begin()到L2.end()复制到L4

    /*重新分配值*/
    L0.assign(4,1);//4个1

    /*插入*/
    L0.push_back(3);//链表尾插入
    L0.push_front(2);//链表头插入
    L0.insert(++L0.begin(),2,5);//在指定的位置插入2个5

    /*获取元素*/
    int& front = L0.front();//返回第一个元素的引用
    int& back = L0.back();//返回最后一个元素的引用
    list<int>::iterator begin = L0.begin();//返回第一个元素的指针
    list<int>::iterator end = L0.end();//返回最后一个元素的指针

    /*删除*/
    L1.pop_back();//删除链表尾元素
    L1.pop_front();//删除链表头元素
    L1.erase(L1.begin());//删除某个元素
    L1.erase(++L1.begin(),--L1.end());//删除指定区域的元素
    L1.insert(L1.begin(),3,2);
    L1.remove(2);//从L1中删除所有的2
    L1.clear();//清除所有元素

    /*交换两个链表*/
    L0.swap(L1);

    /*合并两个链表*/
    L1.merge(L2);

    /*排序*/
    L1.sort(greater <int >());

    /*反转*/
    L1.reverse();

    /*去除唯一值*/
    L1.unique();

    /*链表大小的操作*/
    L1.size();//链表中元素的个数
    L1.max_size();//链表的总容量
    L1.empty();//判断链表是否为空
    L1.resize(10,-1);//重塑长度为10,新的结点使用-1填充
    L1.resize(3);//重塑长度为3,将后面的结点去掉

    /*遍历*/
    list<int>::iterator iter;
    iter = L1.begin();
    while(iter!=L1.end()){
        cout<<*iter++<<" ";
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/bqw18744018044/article/details/81712225