[STL]List的實現

STL(Standard template Library):c++的標準模板庫


STL是算法和數據結構的軟件框架,它包含了六大組件:算法、迭代器、容器、仿函數、配接器、空間配置器。

迭代器:我們可以把迭代器相當于智能指針,(其實指針也就是一個迭代器)迭代器的類型有:前向迭代器(適用于單鏈表),雙向迭代器(適用于雙向鏈表),隨機迭代器(隨機指向),反向迭代器。

容器:像vector,list,map,set這些都屬于容器。分為序列式容器、關聯式容器及其他容器。

序列式容器:vector、list、deque、string

關聯式容器:set、map、multiset、multimap、hash_set、hash_map、hash_multiset、hash_multimap

其他容器:stack、queue、bitset

仿函數我們之前在冒泡排序的時候用opertor()模擬實現仿函數,來實現排序的升序和降序。

配接器:是一種設計模式,它在原有類型的基礎上擴展成為另一個接口,使原本因為接口不兼容而不能合作的類型可以一起工作。就類似于電源適配器一樣。這里有應用于容器的適配器,應用于仿函數的適配器,應用于配接器的適配器等。

空間配置器:用戶數據都是保存在內存中的,那么內存的申請釋放(malloc/free)工作都是由“空間配置器”承擔的。標準c++中提供了std::allocator類。

我們今天要模擬實現STL中的list:(STL庫中的list是一個雙向循環且帶頭節點的鏈表)

它的節點原型是這樣的:

template<typename T>
struct ListNode
{
?? ?struct ListNode* _next;???????????? //指向下一個節點,即后繼節點
?? ?struct ListNode* _prev;???????????? //指向前一個節點,即前驅節點
?? ?T _data;
?? ?ListNode(const T& data)
?? ??? ?:_data(data)
?? ??? ?,_next(NULL)
?? ??? ?,_prev(NULL)
?? ?{}
};

我們還要用到迭代器,重載了++、--、*、->、==、!=等操作符。主要實現了以下函數:


begin:指向的是第一個元素的位置,即頭節點的下一個位置;

end:指向的是最后一個元素的下一個位置,即頭節點的位置。

如圖:


對于迭代器,還有一個重要的問題就是迭代器失效的問題,當然迭代器失效和指針指向未知區域的道理是一樣的。存在的原因是刪除的時候,在鏈表中,你刪除一個元素后,指針必須修改位置,即保存起來以便找到下一個位置。

舉個例子(迭代器失效):

//list.cpp

#include<iostream>
using namespace std;
#include<list>
#include<algorithm>void Print(list<int> l)
{list<int>::iterator it = l.begin();while(it != l.end()){cout<<*it<<" ";++it;}
}int main()
{list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);list<int>::iterator it = l.begin();while(it != l.end()) {if(*it == 2) {l.erase(it);      //it刪除后不知道指向哪里}++it;}Print(l);return 0;
}

看一下監視窗口:

刪除前:


刪除后:


那么怎么解決迭代器失效問題呢?

只要保存之前it的指向,以便找到下一個指向就ok啦。

	list<int>::iterator it = l.begin();while(it != l.end()){if(*it == 2){it = l.erase(it);       //此處用it來接收解決迭代器失效問題}++it;}

運行結果



再來說說list,對于庫里邊的list的函數,如push_back,pop_back,push_front,pop_front,Insert,Erase等函數,下面一 一實現一下哦。

//List.h

#pragma once
#include<iostream>
using namespace std;
template<typename T>
struct ListNode
{struct ListNode* _next;struct ListNode* _prev;T _data;ListNode(const T& data):_data(data),_next(NULL),_prev(NULL){}
};template<typename T,typename Ref,typename Ptr>
struct ListIterator
{typedef ListNode<T> Node;typedef ListIterator<T,T&,T*> Iterator;typedef ListIterator<T,const T&,const T*> ConstIterator;typedef ListIterator<T,Ref,Ptr> Self;ListIterator(Node* node):_node(node){}bool operator==(const Self& x){return _node == x._node;}bool operator!=(const Self& x){return _node != x._node;}Ref operator*(){return (*_node)._data;}Ref operator*() const{return (*_node)._data;}Ptr operator->(){return &(*_node)._data;}Self& operator++(){_node = (*_node)._next;return *this;}Self operator++(int){Self tmp = *this;++(*this);return tmp;}Self& operator--(){_node = (*_node)._prev;return *this;}Self operator--(int){Self tmp = *this;--(*this);return tmp;}Node* _node;
};template<typename T>
class List
{
public:typedef ListNode<T> Node;typedef ListIterator<T,T&,T*> Iterator;typedef ListIterator<T,const T&,const T*> ConstIterator;
public:Node* BuyNode(const T& data){return new Node(data);}
public:List():_head(BuyNode(T())){_head->_next = _head;_head->_prev = _head;}
public:Iterator Begin()              {return (*_head)._next;}Iterator End(){return _head;}ConstIterator Begin() const{return (*_head)._next;}ConstIterator End() const{return _head;}public:void PushBack(const T& data)              //尾插{Node* tmp = BuyNode(data);Node* tail = _head->_prev;tail->_next = tmp;tmp->_prev = tail;tmp->_next = _head;_head->_prev = tmp;}void PopBack()                //尾刪{Node* del = _head->_prev;Node* pre = del->_prev;Node* next = del->_next;pre->_next = next;next->_prev = pre;delete del;}void PushFront(const T& data)          //頭插{Node* tmp = BuyNode(data);Node* next = _head->_next;_head->_next = tmp;tmp->_prev = _head;tmp->_next = next;next->_prev = tmp;}void PopFront()               //頭刪{Node* prev = _head->_prev;Node* next = _head->_next;prev->_next = next;next->_prev = prev;_head = next;}Iterator Insert(Iterator pos,const T& data)      //某一個位置前插入{Node* tmp = BuyNode(data);Node* prev = pos._node->_prev;Node* cur = pos._node;prev->_next = tmp;tmp->_prev = prev;tmp->_next = cur;cur->_prev = tmp;return tmp;}ConstIterator Insert(ConstIterator pos,const T& data)      //某一個位置前插入{Node* tmp = BuyNode(data);Node* prev = pos._node->_prev;Node* cur = pos._node;prev->_next = tmp;tmp->_prev = prev;tmp->_next = cur;cur->_prev = tmp;return tmp;}Iterator Erase(Iterator pos)            //刪除某個位置{assert(pos._node && pos._node != _head);    //判斷節點是否為空,或只剩一個頭節點Node* prev = pos._node->_prev;Node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;return Iterator(next);           //返回下一個位置}bool Empty()        //判斷鏈表是否為空{return _head == _head->_next;}T& Front(){return _head->_next->_data;}T& Back(){return _head->_prev->_data;}const T& Front() const{return _head->_next->_data;}const T& Back() const{return _head->_prev->_data;}void Swap(List<T>& l){swap(_head,l._head);}template<typename InputIterator>void Insert(Iterator pos,InputIterator first,InputIterator last){while(first != last){Insert(pos,*first);++first;}}void Insert(Iterator pos,ConstIterator first,ConstIterator last)  //在pos位置插入一段區間{for(;first != last;++first)Insert(pos,*first);}
private:Node* _head;
};void PrintList(List<int>& l)
{List<int>::Iterator it = l.Begin();while(it != l.End()){cout<<*it<<" ";++it;}cout<<endl;
}


//List.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
#include<vector>
int main()
{List<int> l;List<int> l1;const List<int> l3;l.PushBack(1);l.PushBack(2);l.PushBack(3);l.PushBack(4);l.PopBack();PrintList(l);l.PushFront(0);PrintList(l);l.PopFront();l.Insert(l.End(),4);l.Insert(l.Begin(),0);PrintList(l);cout<<"Front:"<<l.Front()<<endl;cout<<"Back:"<<l.Back()<<endl;cout<<"Empty:"<<l.Empty()<<endl;l1.Swap(l);PrintList(l1);PrintList(l);l.PushBack(10);l.PushBack(11);l.PushBack(12);l1.Insert(l1.Begin(),l.Begin(),l.End());PrintList(l1);vector<int> v;v.push_back(55);v.push_back(66);l1.Insert(l1.Begin(),v.begin(),v.end());PrintList(l1);char str[] = {'a','b'};l1.Insert(l1.Begin(),str,str+2);PrintList(l1);return 0;
}

運行結果:


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/382776.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/382776.shtml
英文地址,請注明出處:http://en.pswp.cn/news/382776.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python 獲取windows上 網絡連接信息 ip dhcp dns gateway

import socket import os import re def get_host_ip():"""查詢本機ip地址:return:"""try:s socket.socket(socket.AF_INET,socket.SOCK_DGRAM)s.connect((8.8.8.8,80))# 能提取出本機ip 通過本機ip提取出其他設置ip s.getsockname()[0]# ip地…

vc++6.0的應用程序打不開腫么辦

今天早起&#xff0c;有同學問到我關于vc6.0的安裝過程中遇到的問題&#xff0c;我聽了之后想想還是寫篇博客給大家看一下吧。因為我之前也遇到過類似的問題。當時也是挺著急的。 大家遇到的問題估計就是這樣吧~~&#xff08;下載后打不開&#xff09; 請看-->解決步驟&…

【數據結構】廣義表

一、問題概述 廣義表是非線性的數據結構&#xff0c;是由若干個元素組合而成的&#xff0c;廣義表中可以有子表&#xff0c;類似這樣的&#xff1a; 我們以C(a,b,(c,d))為例&#xff0c;將它定義為這樣的數據結構&#xff1a; 我們會給定字符串的形式&#xff0c;如&#xff…

centos升級之共享文件夾

vmware-hgfsclient vmhgfs-fuse .host:/share /mnt/hgfs 如果不行的話 cd /mnt mkdir hgfs 把上面的在執行一次

批處理創建程序的快捷方式

"D:\AppServ\timer\win_cron_zq\定時.exe" 這是應用程序timer.lnk" 這是快捷方式的名稱 echo ThePath "D:\AppServ\timer\win_cron_zq\定時.exe">aaa.vbs echo lnkname "timer.lnk">>aaa.vbs echo WS "Wscript.Shell&quo…

【數據結構】普通二叉樹的實現

一、問題概述 樹是n個有限個數據的集合&#xff0c;形如&#xff1a; 它像不像倒著的樹呢&#xff1f;我們把它看成是一種數據結構----樹。它的第一個節點稱作樹的根&#xff0c;最底下的那些節點稱作樹的葉子。 我們今天所要研究的是二叉樹&#xff0c;即父節點最多只有兩個孩…

windows 下 安裝mysql 出現 “ ERROR 1045 (28000): Access denied for user ‘root’@‘localhost’ (using password

這個問題是在Windows下安裝MySQL服務時遇到的&#xff0c;使用MySQl綠色版進行安裝的&#xff0c;安裝完成后&#xff0c;連接到MySQL服務時輸入命令 “ mysql -uroot -p ” &#xff0c;因為時第一次登錄&#xff0c;未設置密碼&#xff0c;直接回車&#xff0c;就遇到了這個問…

setitimer用法說明

函數原型&#xff1a; int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value) 函數作用&#xff1a; 可用來實現延時和定時的功能 頭文件&#xff1a; #include <sys/time.h> 參數詳解 用一把&#xff1a;一個例子 #include &…

哈希表(閉散列、拉鏈法--哈希桶)

哈希表&#xff0c;也稱散列表&#xff0c;是一種通過key值來直接訪問在內存中的存儲的數據結構。它通過一個關鍵值的函數&#xff08;被稱為散列函數&#xff09;將所需的數據映射到表中的位置來訪問數據。 關于哈希表&#xff0c;主要為以下幾個方面&#xff1a; 一、哈希表…

僵尸進程的產生和SIGCHLD信號

核心句子 子進程在終止時會給父進程發SIGCHLD信號,該信號的默認處理動作是忽略,父進程可以自 定義SIGCHLD信號的處理函數。 僵尸進程的產生&#xff1a; #include "head.h" #include <unistd.h> #include <signal.h>int main() {key_t key ftok(&quo…

windows 通過批處理 修改環境變量

echo off setlocal enabledelayedexpansion set remain%path% ::待查找字符串 set toAddD:\ffmpeg2\ffmpeg-4.1.3-win64-shared\bin ::標記,默認沒有重復 set findedfalse :loop for /f "tokens1* delims;" %%a in ("%remain%") do (::如果找到相同的了if…

海量數據處理--位圖(BitMap)

對于海量數據這個詞&#xff0c;大家不難理解吧。主要是針對給定的數據量特別大&#xff0c;占用內存特別大的情況。那么和位圖有什么關系呢。看下面一個騰訊的海量數據的例子吧。 例&#xff1a;給40億個不重復的無符號整數&#xff0c;沒排過序。給一個無符號整數&#xff0…

ps命令與top命令參數意義詳解

文章目錄1.ps -l2.ps aux3.top面試經常被問道&#xff0c;特別是top。1.ps -l 參數解釋F代表這個程序旗標 (process flags)&#xff0c;說明這個程序的總結權限&#xff0c;常見號碼有&#xff1a;o 若為 4 表示此程序的權限為 root &#xff1b;o 若為 1 則表示此子程序僅進行…

python 打包成exe 程序的方法. 轉

轉自 https://blog.csdn.net/lzy98/article/details/83246281

哈希拓展--布隆過濾器

一、問題概述 布隆過濾器是由布隆提出來的&#xff0c;是由一個很長的二進制序列和一系列的映射函數組成。主要用于檢測一個元素是否在一個集合中。當然在設計計算機軟件時&#xff0c;我們也經常會判斷一個元素是否在一個集合中。比如&#xff1a;在字處理軟件中&#xff0c;…

開啟一個新的命令行窗口

1&#xff0c;start cmd /k echo Hello, World!2&#xff0c;start cmd /C pause區別是第二種執行完畢以后&#xff0c;新開的窗口會自動關閉&#xff0c;第一種則不會

C語言中 \r, \n, \b

\r\n 和 \n 區別 &#xff08;重新排版整理&#xff09; \r回車符\n換行符計算機還沒有出現之前&#xff0c;有一種叫做電傳打字機&#xff08;Teletype Model 33&#xff09;的玩意&#xff0c;每秒鐘可以打10個字符。但是它有一個問題&#xff0c;就是打完一行換行的時候&am…

排序(Sort)--【一】

排序&#xff0c;對于大家再熟悉不過了吧。我們之前在學習c語言的時候接觸過的冒泡排序&#xff0c;選擇排序等。今天給大家介紹兩種新的排序。 1、直接插入排序 升序排列&#xff1a;將第一個數確定好&#xff0c;從下標為1的數開始插入&#xff0c;如果插入的數比前一個數大…

用python os.system 執行 批處理的時候, 出現的一些問題

如果 在一個py文件里面 , 假設用 三條語句 os.system(a.bat) os.system(b.bat) os.system(c.bat)這樣的話 只會最后一條生效.