1. 程式人生 > >C++ STL之list雙向連結串列容器

C++ STL之list雙向連結串列容器

不同於採用線性表順序儲存結構的vector和deque容器,list雙向連結串列中任一位置的元素查詢、插入和刪除,都具有高效的常數階演算法時間複雜度O(1)。

  1. list技術原理 為了支援前向和反向訪問list容器的元素,list採用雙向迴圈的連結串列結構組織資料元素,連結串列的每個節點包括指向前驅的指標、實際資料和指向後繼的指標等資料域。 在這裡插入圖片描述 list的前向鏈,由頭節點→第1個節點→第2個節點→…第n個節點→頭節點構成迴圈。 list的反向鏈,則由第n個節點→第n-1個節點→…→頭節點→第n個節點構成迴圈。n為list的節點個數,整個連結串列的儲存位置由頭指標指出,它指向頭節點。
  2. 應用基礎 list物件的建立,初始化賦值方法與vector相同,list的交換與deque相同,這裡直接跳過。 2.1元素的遍歷訪問 由於連結串列中的資料需要一個個元素進行遍歷,因此,list元素的遍歷只使用迭代器的方式進行。上程式碼:
#include <QCoreApplication>
#include <iostream>
#include <list>
using namespace std;
struct Student{
    char *name;
    int age;
    char *city;
    char *tel;
};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Student s[] = {
        {"符符",18,"上海市","156624"},
        {"介介",20,"北京市","152534"},
        {"貝貝",25,"深圳市","453545"},
    };
    //將資料插入連結串列
    list<Student> l;
    l.push_back(s[0]);
    l.push_back(s[1]);
    l.push_back(s[2]);
    //遍歷列印連結串列元素
    list<Student>::iterator i,iend;
    iend=l.end();
    cout << "姓名 年齡 城市 電話" << endl;
    cout << "----------------------------" << endl;
    for(i=l.begin();i!=iend;i++)
    {
        cout << (*i).name << " ";
        cout << (*i).age << " ";
        cout << (*i).city << " ";
        cout << (*i).tel << " " << endl;
    }
    cout << "----------------------------" << endl;
    return a.exec();
}

執行結果: list遍歷結果 2.2元素的插入 由於list連結串列元素的插入不需要對其他元素進行移位拷貝,除了push_back函式在尾部新增元素外,list還提供了在鏈首插入元素的push_front函式和在任意迭代器位置的插入insert()函式。

#include <QCoreApplication>
#include <iostream>
#include <list>
using namespace std;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    list<int> l;
    l.push_back(6);
    l.push_back(8);
    l.push_back(9);
    list<int>::iterator i,iend;
    i=l.begin();
    i++;
    l.insert(i,7);    //在6的後面插入7
    l.push_front(5);     //在鏈首插入5
    iend=l.end();
    for(i=l.begin();i!=iend;i++)
    {
        cout << *i << ' ';
    }
    return a.exec();
}

輸出結果: 在這裡插入圖片描述 2.3元素的反向遍歷和刪除 由於list容器的迭代器具有"–"操作,因此也定義了反向迭代器。用反向迭代器來進行連結串列的遍歷。

#include <QCoreApplication>
#include <iostream>
#include <list>
using namespace std;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    list<int> l;
    l.push_back(5);
    l.push_back(6);
    l.push_back(7);
    l.push_back(8);
    l.push_back(9);
    l.push_back(9);
    l.push_back(9);
    l.push_back(10);
    list<int>::reverse_iterator ri,rend;
    rend=l.rend();
    cout << "反向遍歷:";
    for(ri=l.rbegin();ri!=rend;ri++)
    {
        cout << *ri << " ";
    }
    cout << endl;
    list<int>::iterator i,iend;
    i=l.begin();
    i++;
    l.erase(i);     //刪除6
    l.pop_back();   //刪除末元素10
    l.pop_front();   //刪除首元素5
    l.remove(9);     //刪除所有值為9的元素
    iend=l.end();
    for(i=l.begin();i!=iend;i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    return a.exec();
}

執行結果: 在這裡插入圖片描述 2.4list的排序與歸併 list 提供的void sort函式,將連結串列中的元素按"<"關係進行排序,較小的排在前面。 list連結串列元素的排序,是將list連結串列分割成若干部分進行子排序,然後通過歸併處理,實現list的所有元素的排序。為此,list容器提供了splice和merge的歸併函式。

void splice(iterator position,list& x) //將x的連結串列歸併到當前list連結串列的position之前,list物件x將被清空 void splice(iterator position,list&,iterator i)//將一個list的迭代器i值所指的元素,歸併到當前list連結串列中,並將被歸併的元素從原連結串列中刪除 void merge(list& x)//將list物件x的連結串列歸併到當前list連結串列中,並清空x的連結串列。從merge函式的原始碼可知,只有當前的list連結串列和x均預先按元素的"<“關係排好序,merge函式才有意義,歸併後的連結串列也是按”<"關係排列。

上程式碼:

#include <QCoreApplication>
#include <iostream>
#include <list>
using namespace std;
void print(list<int>& l)
{
    list<int>::iterator i,iend;
    iend=l.end();
    for(i=l.begin();i!=iend;i++)
    {
        cout << *i << " ";
    }
    cout<< endl;
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    list<int> l;
    l.push_back(13);
    l.push_back(6);
    l.push_back(7);
    l.push_back(15);
    l.push_back(9);
    l.push_back(8);
    l.push_back(9);
    l.push_back(10);
    cout << "未排序前:";
    print(l);
    l.sort();   //從小到大排序
    cout << "排序後:";
    print(l);
    list<int> carry;
    carry.splice(carry.begin(),l,l.begin());   //將l的第一個元素歸併到carry的首元素,並將l的首元素刪除
    cout << "carry的連結串列元素為:";
    print(carry);
    cout << "l的連結串列元素為:";
    print(l);
    list<int> x;
    x.push_back(30);
    x.push_back(31);
    x.push_back(32);
    l.merge(x);                      //將x連結串列裡的元素歸併到l,並清空x
    cout << "x的連結串列元素為:";
    print(x);
    cout << "l的元素為:";
    print(l);
    return a.exec();
}

執行結果: 在這裡插入圖片描述

3.小結 list雙向連結串列容器採用雙向連結串列的資料結構來儲存資料,可高效查詢、插入和刪除容器元素。list提供的splice和merge歸併函式,可用於連結串列的元素排序。