欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++實(shí)現(xiàn)list增刪查改模擬的示例代碼

 更新時(shí)間:2023年12月26日 09:29:04   作者:小宇成長(zhǎng)錄  
本文主要介紹了C++實(shí)現(xiàn)list增刪查改模擬,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

本篇博客采用SGI版本,同時(shí)考慮到看到此篇博客大部分為初學(xué)者,為此博主僅僅給出有用片段。C++:list增刪查改模擬實(shí)現(xiàn)就是用C++復(fù)寫雙鏈表,非常簡(jiǎn)單。難點(diǎn)主要在迭代器實(shí)現(xiàn)

一、list底層雙鏈表驗(yàn)證、節(jié)點(diǎn)構(gòu)造

1.1 list底層數(shù)據(jù)結(jié)構(gòu)

list底層使用什么數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn)的呢?我們先來(lái)看看SGI庫(kù)中l(wèi)ist的成員函數(shù)和初始化吧。

在這里插入圖片描述

我們發(fā)現(xiàn)list實(shí)現(xiàn)中,只有node一個(gè)成員變量。構(gòu)造函數(shù)構(gòu)造出一個(gè)頭尾相連的哨兵位。同時(shí)驗(yàn)證了list底層是一個(gè)帶哨兵位的雙鏈表。

1. 2 節(jié)點(diǎn)構(gòu)造

節(jié)點(diǎn)和雙鏈表一樣有三個(gè)成員:節(jié)點(diǎn)數(shù)據(jù)、指向前一個(gè)節(jié)點(diǎn)(prev)、指向后一個(gè)節(jié)點(diǎn)(next)。

//節(jié)點(diǎn)
template<class T>
struct List_node
{
	T _data;
	List_node<T>* _prev;
	List_node<T>* _next;

	List_node(const T& x = T())
		:_data(x)
		,_prev(nullptr)
		,_next(nullptr)
	{}
};

小tips:

  • 我們這里類名和庫(kù)中一樣(List_node),后續(xù)在其他類中使用時(shí)在typedef。
  • 這里類名使用struct而不是class原因在于struct默認(rèn)訪問(wèn)權(quán)限為公有,后續(xù)其他類只都需要大量使用。如果使用class需要使用大量友元類,過(guò)于繁瑣。

二、迭代器封裝實(shí)現(xiàn)(重點(diǎn)、難點(diǎn))

2.1 前置說(shuō)明

  • 我們知道迭代器的最大用途便是遍歷數(shù)據(jù)。但何時(shí)停在,迭代器指向空間存儲(chǔ)數(shù)據(jù)時(shí)是什么…導(dǎo)致我們需要使用!=、++、*等操作。但自定義類型是無(wú)法支持使用這些操作符的。為此給出的解決辦法是:封裝加運(yùn)算符重載。
  • 迭代器使用上分為普通迭代器和const迭代器(還分為單向迭代器、雙向迭代器和隨機(jī)訪問(wèn)迭代器)。其中一種最簡(jiǎn)單的實(shí)現(xiàn)方式就是實(shí)現(xiàn)兩個(gè)類。但。。。我們知道兩個(gè)迭代器的不同之處在于const迭代器無(wú)法修改數(shù)據(jù),只是j相關(guān)借口(這里有*、->)不同而已便實(shí)現(xiàn)兩個(gè)類未免過(guò)于“小題大做”。
    所以接下來(lái)我們來(lái)看看庫(kù)中是如何巧妙的解決這個(gè)問(wèn)題吧!

    在這里插入圖片描述

2.2 迭代器實(shí)現(xiàn)

前置說(shuō)明中以及解決了如何實(shí)現(xiàn)一個(gè)類達(dá)到目的。接下來(lái)的實(shí)現(xiàn)過(guò)于簡(jiǎn)單就不單獨(dú)說(shuō)明了。

//迭代器封裝
template<class T, class Ref, class Ptr>
struct __list_iterator
{
	typedef List_node<T> Node;//節(jié)點(diǎn)類名重命名
	//由于迭代器實(shí)現(xiàn)中,如++、--等重載函數(shù)返回值類型為_(kāi)_list_iterator,名字過(guò)長(zhǎng),這里我們重命名self意味自身
	typedef __list_iterator<T,Ref, Ptr> self;
	Node* _node;//成員變量

	__list_iterator(Node* node)//構(gòu)造出一個(gè)節(jié)點(diǎn)
		:_node(node)
	{}

	//前置++
	self& operator++()
	{
		_node = _node->_next;
		return *this;
	}
	//前置--
	self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}
	
	//后置++
	self operator++(int)
	{
		self tmp(*this);
		_node = _node->_next;
		return tmp;
	}
	//后置--
	self operator--(int)
	{
		self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}
	
	//解引用操作符重載
	Ref operator*()
	{
		return _node->_data;
	}
	
	//用于訪問(wèn)迭代器指向?qū)ο笾写鎯?chǔ)的是自定義類型
	Ptr operator->()
	{
		return &_node->_data;
	}

	bool operator!=(const self& s)
	{
		return _node != s._node;
	}

	bool operator==(const self& s)
	{
		return _node == s._node;
	}
};

三、list實(shí)現(xiàn)

3.1 基本框架

list模擬中,我們和庫(kù)中一樣,給出一個(gè)頭節(jié)點(diǎn)_head、_size兩個(gè)成員變量。同時(shí)我們將節(jié)點(diǎn)、迭代器進(jìn)行重命名。迭代器重命名不是單純圖方便,更重要的是提供統(tǒng)一接口(例如sting、vector、set等接口都一樣),屏蔽底層的變量和成員函數(shù)屬性,實(shí)現(xiàn)過(guò)程和差異。

//list模擬實(shí)現(xiàn)
template<class T>
class List
{
	typedef List_node<T> Node;
public:
	//迭代器重命名,提供統(tǒng)一的接口,屏蔽底層實(shí)現(xiàn)細(xì)節(jié)和差異
	typedef __list_iterator<T, T&, T*> iterator;
	typedef __list_iterator<T, const T&, const T*> const_iterator;
private:
	Node* _head;//頭節(jié)點(diǎn)
	int _size;
};

3.2 迭代器和const迭代器

下面是begin()、end()指向一個(gè)有效雙線表的位置。

在這里插入圖片描述

實(shí)現(xiàn):

const_iterator begin()const
{
	//return const_iterator(_head->_next);或
	return _head->_next;//單參數(shù)類型支持隱式類型轉(zhuǎn)換
}

const_iterator end()const
{
	return _head;
}

iterator begin()
{
	return _head->_next;
}

iterator end()
{
	return _head;
}

3.2 構(gòu)造函數(shù)、析構(gòu)函數(shù)、拷貝構(gòu)造、賦值重載

3.2.1 構(gòu)造函數(shù)

構(gòu)造函數(shù)的實(shí)現(xiàn)和開(kāi)頭中看到的一樣:構(gòu)造函數(shù)中調(diào)用一個(gè)函數(shù)(empty_Init)來(lái)是實(shí)現(xiàn)。empty_Init()用來(lái)完成初始化。(empty_Init()函數(shù)后續(xù)其他接口也要調(diào)用)

//初始化
void empty_Init()
{
	_head = new Node;
	_head->_next = _head;
	_head->_prev = _head;

	_size = 0;
}

//無(wú)參構(gòu)造
List()
{
	empty_Init();
}

3.2.2 析構(gòu)函數(shù)

析構(gòu)函數(shù)我們調(diào)用一個(gè)clear函數(shù)來(lái)將數(shù)據(jù)全部清空,在將_head變量釋放。

//析構(gòu)函數(shù)
~List()
{
	clear();
	delete _head;
	_head = nullptr;
}

void clear()
{
	iterator it = begin();
	while (it != end())
	{
		it = erase(it);
	}
}

3.2.3 拷貝構(gòu)造

拷貝構(gòu)造時(shí)首先要初始化出一個(gè)節(jié)點(diǎn),然后將需要拷貝的數(shù)據(jù)依次尾插即可(尾插接口后續(xù)給出實(shí)現(xiàn))

//拷貝構(gòu)造
List(const List<T>& It)
{
	empty_Init();
	for (auto e : It)
	{
		push_back(e);
	}
}

3.2.4 賦值重載

賦值重載有很多方式。比較簡(jiǎn)單的參數(shù)我們直接傳值,然后將待賦值的變量和傳值傳參省生成的臨時(shí)變量的數(shù)據(jù)進(jìn)行交換即可。

void swap(const List<T>& It)
{
	std::swap(_head, It._head);
}

//賦值重載
List<T>& operator=(const List<T> It)
{
	swap(It);
	return *this;
}

3.3 任意位置插入、任意位置刪除、尾插、尾刪、頭插、頭刪

3.3.1任意位置插入

首先new出待插入節(jié)點(diǎn)newnode,然后將pos前一個(gè)節(jié)點(diǎn)prev、newnode、pos相連。最后++_size即可。

在這里插入圖片描述

iterator insert(iterator pos, const T& x)
{
	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* newnode = new Node(x);

	prev->_next = newnode;
	newnode->_prev = prev;

	newnode->_next = cur;
	cur->_prev = newnode;
	_size++;
	return newnode;
}

3.3.2任意位置插入刪除

將待刪除數(shù)據(jù)的前后節(jié)點(diǎn)先保存起來(lái),然后將刪除pos處節(jié)點(diǎn),再將前后節(jié)點(diǎn)連接起來(lái)。最后–_size即可。

iterator erase(iterator pos)
{
	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* next = cur->_next;
	delete cur;
	prev->_next = next;
	next->_prev = prev;

	_size--;
	return next;
}

3.3.3 尾插、尾刪、頭插、頭刪

尾插、尾刪、頭插、頭刪都是復(fù)用任意位置插入、任意位置刪除接口。

void push_back(const T& x)
{
	insert(end(), x);
}

void push_front(const T& x)
{
	insert(begin(), x);
}

void pop_back()
{
	erase(--end());
}

void pop_front()
{
	erase(begin());
}

四、list功能完善

4.1 迭代器operator->()

我們先來(lái)看看下面這段代碼對(duì)嗎?

struct AA
{
	AA(int a1 = 0, int a2 = 0)
		:_a1(a1)
		,_a2(a2)
	{}

	int _a1;
	int _a2;
};

void test_list3()
{
	list<AA> lt;
	lt.push_back(AA(1, 1));
	lt.push_back(AA(2, 2));
	lt.push_back(AA(3, 3));

	list<AA>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout<<*it<<" ";
		++it;
	}
	cout << endl;
}

由于list沒(méi)有重載<<,所以對(duì)存儲(chǔ)的是自定義類型之間訪問(wèn)會(huì)編譯報(bào)錯(cuò)。
那我們重載下<<運(yùn)算符不就行了嗎?很不幸的是C++庫(kù)在list中不支持<<,很大原因也在于編譯器不知到我們?nèi)绾稳?shù)據(jù)

所以對(duì)于自定義類型我們可以先解引用在去訪問(wèn)成員,也可以在迭代器中重載operator->()函數(shù)。但需要注意的是編譯器隱藏了一個(gè)->,具體原生行為如下:

struct AA
{
	AA(int a1 = 0, int a2 = 0)
		:_a1(a1)
		,_a2(a2)
	{}

	int _a1;
	int _a2;
};

void test_list3()
{
	list<AA> lt;
	lt.push_back(AA(1, 1));
	lt.push_back(AA(2, 2));
	lt.push_back(AA(3, 3));

	list<AA>::iterator it = lt.begin();
	while (it != lt.end())
	{
		//cout << (*it)._a1<<" "<<(*it)._a2 << endl;
		cout << it->_a1 << " " << it->_a2 << endl;
		//上面編譯器訪問(wèn)成員變量的真正行為如下:
		//cout << it.operator->()->_a1 << " " << it.operator->()->_a1 << endl;
		++it;
	}
	cout << endl;
}

4.2 打印數(shù)據(jù)

//大多數(shù)情況模板是class還是typename是一樣的,但當(dāng)有未實(shí)例化模板時(shí),必須使用typename
//template<typename T>
void print_list(const list<T>& lt)
{
	// list<T>未實(shí)例化的類模板,編譯器不能去他里面去找
	// 編譯器就無(wú)法list<T>::const_iterator是內(nèi)嵌類型,還是靜態(tài)成員變量
	// 前面加一個(gè)typename就是告訴編譯器,這里是一個(gè)類型,等list<T>實(shí)例化
	// 再去類里面去取
	typename list<T>::const_iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;  
}

優(yōu)化:上面打印數(shù)據(jù)是針對(duì)list,下面是針對(duì)容器的。

// 模板(泛型編程)本質(zhì),本來(lái)應(yīng)該由我們干的活交給編譯器
template<typename Container>
void print_container(const Container& con)
{
	typename Container::const_iterator it = con.begin();
	while (it != con.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

五·、所有代碼以及測(cè)試用例

giteeC++:list增刪查改模擬實(shí)現(xiàn)代碼以及測(cè)試用例

推薦:giteeC++:list增刪查改模擬實(shí)現(xiàn)代碼(最終版本、感覺(jué)版本?。。。?/a>

到此這篇關(guān)于C++實(shí)現(xiàn)list增刪查改模擬的文章就介紹到這了,更多相關(guān)C++ list增刪查改 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++通過(guò)SQLiteSDK增刪改查的實(shí)現(xiàn)示例

    C++通過(guò)SQLiteSDK增刪改查的實(shí)現(xiàn)示例

    SQLite是一種輕量級(jí)的嵌入式數(shù)據(jù)庫(kù),可以利用SQLiteSDK執(zhí)行數(shù)據(jù)庫(kù)的增刪改查操作,本文主要介紹了C++通過(guò)SQLiteSDK增刪改查,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-03-03
  • QT中大部分部件如何使用舉例詳解

    QT中大部分部件如何使用舉例詳解

    QWidget類是所有用戶界面對(duì)象的基類,被稱為基礎(chǔ)窗口部件,下面這篇文章主要給大家介紹了關(guān)于QT中大部分部件如何使用的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • C++使用string的大數(shù)乘法運(yùn)算(3)

    C++使用string的大數(shù)乘法運(yùn)算(3)

    這篇文章主要為大家詳細(xì)介紹了C++使用string的大數(shù)乘法運(yùn)算,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • C++ ReSharper2021激活碼永久有效

    C++ ReSharper2021激活碼永久有效

    ReSharperC++是為c/c++開(kāi)發(fā)者打造的一款實(shí)用Visual Studio擴(kuò)展插件,這款插件旨在提升開(kāi)發(fā)者的效率,今天給大家分享這款軟件的激活方法,需要C++ ReSharper2021激活碼的朋友參考下本文
    2021-06-06
  • C++中this指針用法詳解及實(shí)例

    C++中this指針用法詳解及實(shí)例

    這篇文章主要介紹了C++中this指針用法詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • C++ 標(biāo)準(zhǔn)模板庫(kù) STL 順序容器詳解

    C++ 標(biāo)準(zhǔn)模板庫(kù) STL 順序容器詳解

    這篇文章主要介紹了C++ 標(biāo)準(zhǔn)模板庫(kù) STL 順序容器詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-05-05
  • Ubuntu20.04安裝使用jsoncpp、json-c庫(kù)的方法實(shí)例

    Ubuntu20.04安裝使用jsoncpp、json-c庫(kù)的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于Ubuntu20.04安裝使用jsoncpp、json-c庫(kù)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作就有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-04-04
  • C語(yǔ)言 棧的表示和實(shí)現(xiàn)詳細(xì)介紹

    C語(yǔ)言 棧的表示和實(shí)現(xiàn)詳細(xì)介紹

    這篇文章主要介紹了C語(yǔ)言 棧的表示和實(shí)現(xiàn)詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • 淺談C++反向迭代器的設(shè)計(jì)

    淺談C++反向迭代器的設(shè)計(jì)

    本文主要介紹了淺談C++反向迭代器的設(shè)計(jì),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Qt數(shù)據(jù)庫(kù)應(yīng)用之實(shí)現(xiàn)通用數(shù)據(jù)庫(kù)請(qǐng)求

    Qt數(shù)據(jù)庫(kù)應(yīng)用之實(shí)現(xiàn)通用數(shù)據(jù)庫(kù)請(qǐng)求

    這篇文章主要為大家介紹了Qt中是如何實(shí)現(xiàn)通用數(shù)據(jù)庫(kù)請(qǐng)求的,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Qt有一定幫助,感興趣的小伙伴可以了解一下
    2022-03-03

最新評(píng)論