線性表

来源:http://www.cnblogs.com/wuhui2356/archive/2017/04/17/6724570.html
-Advertisement-
Play Games

下麵說的線性表主要是線性鏈表,這裡主要將雙向鏈表,單向鏈表迴圈鏈表等是類似的,不再累述。如果發現錯誤,還望不吝指正。 定義 線性表(linear list)是數據結構的一種,一個線性表是n個具有相同特性的數據元素的有限序列。數據元素是一個抽象的符號,其具體含義在不同的情況下一般不同。 在稍複雜的線性 ...


下麵說的線性表主要是線性鏈表,這裡主要將雙向鏈表,單向鏈表迴圈鏈表等是類似的,不再累述。如果發現錯誤,還望不吝指正。

定義

線性表(linear list)是數據結構的一種,一個線性表是n個具有相同特性的數據元素的有限序列。數據元素是一個抽象的符號,其具體含義在不同的情況下一般不同。 在稍複雜的線性表中,一個數據元素可由多個數據項(item)組成,此種情況下常把數據元素稱為記錄(record),含有大量記錄的線性表又稱文件(file)。 線性表中的個數n定義為線性表的長度,n=0時稱為空表。在非空表中每個數據元素都有一個確定的位置,如用ai表示數據元素,則i稱為數據元素ai線上性表中的位序。 線性表的相鄰元素之間存在著序偶關係。如用(a1,…,ai-1,ai,ai+1,…,an)表示一個順序表,則表中ai-1領先於ai,ai領先於ai+1,稱ai-1是ai的直接前驅元素,ai+1是ai的直接後繼元素。當i=1,2,…,n-1時,ai有且僅有一個直接後繼,當i=2,3,…,n時,ai有且僅有一個直接前驅。(來自百度百科)

實現

採用的C++實現整個鏈表的操作過程,對於節點的記憶體的管理使用了C++11中提供的智能指針shared_ptr,以確保不會發生記憶體泄露的情況。

對鏈表操作的實現中採用了兩層封裝,將涉及到指針的操作封裝成了私有方法,避免泄露指針,導致無法控制對象析構的時刻,並且整個鏈表是非線程安全的。

節點數據結構:

template <typename T>
class Node {
public:
	Node() { _prev = nullptr, _next = nullptr; }
	Node(T data) : Node() { _data = data; }
	void set_data(T data) { _data = data; }
	void set_prev(std::shared_ptr<Node<T>> prev) { _prev = prev; }
	void set_next(std::shared_ptr<Node<T>> next) { _next = next; }
	std::shared_ptr<Node<T>> prev() { return _prev; }
	std::shared_ptr<Node<T>> next() { return _next; }
	T data() { return _data; }

private:
	T _data;
	std::shared_ptr<Node<T>> _prev;
	std::shared_ptr<Node<T>> _next;
};

整個表結構:

整個表包含一個指向頭結點的指針和一個指向尾節點的指針,以及表的長度和表的大小的變數。

template <typename T>
class LinearList
{
public:
	LinearList();
     ~LinearList(); void insert_node(T data, int64_t index); void delete_node(int64_t index, T& data); T get_element(int64_t index); int64_t size(); int64_t length(); private: std::shared_ptr<Node<T>> get_element_ptr(int64_t index); void insert_node_ptr(std::shared_ptr<Node<T>> &data, int64_t index); void delete_node_ptr(int64_t index, std::shared_ptr<Node<T>> &data); private: std::shared_ptr<Node<T>> _head; std::shared_ptr<Node<T>> _tail; int64_t _size; int64_t _length; };

插入新節點:  

整個鏈表是一個帶空頭結點的鏈表:

1. 尋找插入點

2. 將待插入節點的next指針指向插入點指向的下一節點

3. 將待插入節點的prev指針指向插入點

4. 如果插入點的next指針不為空(不是頭結點),將插入點的下一節點的prev指針指向帶插入節點

5. 將插入點的next指針指向待插入點

template<typename T>
inline void LinearList<T>::insert_node(T data, int64_t index)
{
	if (index < 0 || index > _length)
	{
		index = _length;
	}
	std::shared_ptr<Node<T>> data_ptr = std::make_shared<Node<T>>(data);
	this->insert_node_ptr(data_ptr, index);
}

template<typename T>
inline void LinearList<T>::insert_node_ptr(std::shared_ptr<Node<T>> &data, int64_t index)
{
	_ASSERTE(!(index < 0 || index > _length));
	std::shared_ptr<Node<T>> tmp_ptr(_head);
	// 查找插入位置
	for (int64_t i = 0; i < index; ++i)
	{
		tmp_ptr = tmp_ptr->next();
	}
	// 將data插入到tmp_ptr的後面
	data->set_next(tmp_ptr->next());
	data->set_prev(tmp_ptr);
	tmp_ptr->next() == nullptr ? tmp_ptr : tmp_ptr->next()->set_prev(data);
	tmp_ptr->set_next(data);
	++_length;
	_size += sizeof(Node<T>);
}

刪除節點:

1.  查找待刪除節點

2. 斷開其prev和next指針

template<typename T>
inline void LinearList<T>::delete_node(int64_t index, T & data)
{
	if (index < 0 || index > _length)
	{
		index = _length;
	}

	std::shared_ptr<Node<T>> tmp_ptr;
	delete_node_ptr(index, tmp_ptr);
	data = tmp_ptr->data();
}

template<typename T>
inline void LinearList<T>::delete_node_ptr(int64_t index, std::shared_ptr<Node<T>>& data)
{
	_ASSERTE(!(index < 0 || index > _length));
	std::shared_ptr<Node<T>> tmp_ptr(_head->next());
	// 查找待刪除節點
	for (int64_t i = 0; i < index; ++i) 
	{
		tmp_ptr = tmp_ptr->next();
	}
	tmp_ptr->prev() == nullptr ? nullptr : tmp_ptr->prev()->set_next(tmp_ptr->next());
	tmp_ptr->next() == nullptr ? nullptr : tmp_ptr->next()->set_prev(tmp_ptr->prev());
	data = tmp_ptr;
	--_length;
	_size -= sizeof(Node<T>);
}

查看某個節點:

template<typename T>
inline T LinearList<T>::get_element(int64_t index)
{
	return get_element_ptr(index)->data();
}

template<typename T>
inline std::shared_ptr<Node<T>> LinearList<T>::get_element_ptr(int64_t index)
{
	if (index < 0 || index > _length) {
		throw new std::exception("Invalid argument index.");
	}
	std::shared_ptr<Node<T>> tmp_ptr(_head->next());
	for (int64_t i = 0; i < index; ++i)
	{
		tmp_ptr = tmp_ptr->next();
	}
	return tmp_ptr;
}

主函數:

int main() {

	LinearList<int> linear_list;
	for (int64_t i = 0; i < 10; i++)
	{
		linear_list.insert_node(i, i);
	}

	std::cout << "遍歷節點:" << std::endl;
	for (int64_t i = 0; i < linear_list.length(); ++i) {
		std::cout << linear_list.get_element(i) << " ";
	}
	std::cout << std::endl << std::endl;

	std::cout << "刪除第2個節點: " << std::endl;
	int data;
	linear_list.delete_node(2, data);
	std::cout << data << std::endl << std::endl;

	std::cout << "第2個節點已刪除,再次遍歷結果為:" << std::endl;
	for (int64_t i = 0; i < linear_list.length(); ++i) {
		std::cout << linear_list.get_element(i) << " ";
	}
	std::cout << std::endl << std::endl;

	std::cout << "刪除第2個節點: " << std::endl;
	linear_list.delete_node(2, data);
	std::cout << data << std::endl << std::endl;

	std::cout << "第2個節點已刪除,再次遍歷結果為:" << std::endl;
	for (int64_t i = 0; i < linear_list.length(); ++i) {
		std::cout << linear_list.get_element(i) << " ";
	}
	std::cout << std::endl << std::endl;

	return 0;
}

運行結果為:

 代碼下載地址:https://github.com/wuhui2356/data_structure/tree/master/LinearList

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 關於這個問題我糾結了很久,每次打開網頁yii\db\Connection::open幾乎都耗時1000ms。 其實這個問題很好解決:只要把config\db.php配置信息里的localhost,改成ip地址就好,可能是地址解析的原因才會耗時那麼久。 ...
  • 在之前我們使用Swift的Perfect框架來開發服務端程式時,聊到了Perfect中的路由配置。而在SpringMVC中的路由配置與其也是大同小異的。說到路由,其實就是將URL映射到Java的具體類中的具體方法,或者映射到具體的JSP文件上。本篇博客主要就闡述瞭如何在SpringMVC中配置路由以 ...
  • 1、簡介 Apached的重寫功能,即是mod_rewrite模塊功能,它是apache的一個模塊。它的功能非常強大,可以操作URL中的所有部分。 因此我們就可以改寫url,給用戶提供一個簡介大方的url,當用戶訪問時可以通過mod_rewrite模塊功能轉換為真正的資源路徑。通過mod_rewri ...
  • PHP常用字元串的操作函數 字元串轉換類函數 addcslashes函數:以C語言風格使用反斜線轉義字元串中的字元 addslashes函數:使用反斜線引用字元串 chop函數:清除字元串中的連續空格 get_html_translation_table函數:返回htmlspecialchars() ...
  • 本節,我們來探討Java中的定時任務Timer和ScheduledExecutorService,它們的基本用法都是比較簡單的,但如果對它們缺乏足夠的瞭解,則很容易墜入其中的一些坑,都有哪些坑呢? ...
  • struts編寫文件下載的代碼 配置struts.xml文件 創建Action類 jsp代碼 在運行中可能遇到的錯誤!!!!! 1、下載文件的文件名顯示成xxx.action或者不是下載文件本來的文件名 可能是獲取文件名的getFileName方法沒有大寫 可能是getFileName方法直接返回f ...
  • web.xml的作用: 1.配置JSP,Servlet,Listener,Filter,標簽庫,JSP屬性 2.配置JAAS授權認證,資源應用,web首頁設置JSP的本質是Servlet(web應用中每個JSP頁面都會由Servlet容器生成對應的Servlet)JSP包括靜態的html頁面代碼和動 ...
  • 訪問控制 public(公開的):可以在類中、子類中、類外訪問。 protected(受保護的):只能在類本身及子類中訪問。 private(私有的):只能在聲明他們的類中進行訪問,私有的類成員不能被子類或者這個類的對象實例直接訪問。 抽象類和方法 在繼承概念被應用在一些場景中,創建一個父類的實例將 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...