數據結構和算法(05)---鏈表(c++)

文章目錄

  • 目錄
    • 鏈表的基本概念
      • 1.數組和鏈表
    • 鏈表的使用
      • 1.鏈表的簡單使用
      • 2.鏈表的進階使用
      • 3.鏈表的高階使用
      • 4.鏈表的其他操作
    • 鏈表容器list
      • 1.list介紹
      • 2. list使用
      • 3. list與vector之間的區別
      • 4.list例子代碼

目錄

  • 數據結構:
    • 邏輯結構:數組,棧,隊列,字符串,樹,圖
    • 存儲結構:順序存儲,鏈式存儲
  • C++常用的數據結構有:string , stack , queue , deque , vector , list , map , iterators.

鏈表的基本概念

鏈表是一種線性表,其在內存中以鏈式結構存儲,所以叫做鏈表。具有插入和刪除方便,但是訪問則必須從鏈表的頭開始。

1.數組和鏈表

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

鏈表的使用

1.鏈表的簡單使用

一個個節點按順序串接起來,就構成了鏈表。顯然這一個個節點是很關鍵的,假設我們要構造一個int類型的鏈表,那么一個節點中就需要包含兩個元素:

  • 一個是當前節點所保存的值,設為int value。
  • 另一個就是指向下一個節點的指針,我們再假設這個節點類是node,那么這個指針就是 node *next。

這里一定不是int *next。因為這個指針指向的下一個元素是一個類的實例,而不是int類型的數據。那么node這個類最簡單的實現就如下:

class node  
{  
public:  int value;  node *next;  node()  {  value = 0;  next = NULL;  }  
}; 

這個類名字為node,包含兩個元素,一個是當前node的值,一個是指向下一個節點的指針,還有一個構造函數,分別將value初始化為0、next初始化為NULL
拿到這個類以后,假設我們生成兩個這個類的實例,node1和node2,再將node1的next指針指向node2,就構成了有兩個元素的鏈表。這樣如果我們拿到node1這個節點,就可以通過next指針訪問node2。比如下面的代碼

#include <iostream>
#include <deque>using namespace std;class node{
public:int value;//鏈表節點的數據域node* next;//用于指向下一個節點,是鏈表中的指針域node():value(0),next(NULL){};//默認構造函數node(int value):value(value),next(NULL){};//帶參數的構造函數 ~ node(){cout<<"delete the node!!!"<<endl;delete next; // 刪除節點的指針域 } 
}; int main(){node mNode1(1),mNode2(2),mNode3(3),mNode4(4);mNode1.next = &mNode2;mNode2.next = &mNode3;mNode3.next = &mNode4;cout<<"the value of node3 is :"<<mNode3.value<<endl;  //直接輸出節點 cout<<"the value of node3 is :"<<mNode1.next->next->value<<endl;  //通過鏈表查找 return 0;
} 

the value of node3 is :3
the value of node3 is :3
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
在這里插入圖片描述

2.鏈表的進階使用

上述這樣就構成了一個最簡單的鏈表,如果還有新的節點出現,那么就如法炮制,鏈在表尾或者表頭,當然插在中間也是沒問題的。

但是這樣還有個問題就是node1和node2是我們提前聲明好的,而且知道這兩個實例的名稱,如果我們需要1000甚至跟多節點,這種方式顯然是不科學的,而且在很多時候,我們都是動態生成一個類的實例,返回的是這個實例的首地址。

下面的代碼我們用一個for循環,生成11個節點,串起來形成一個鏈表
原理就是先生成一個頭結點,然后動態生成10個節點,每生成一個節點,就將這個節點指向頭結點,然后更新頭結點為當前節點

#include <iostream>
#include <deque>using namespace std;class Node{
public:int value;//鏈表節點的數據域Node* next;//用于指向下一個節點,是鏈表中的指針域Node():value(0),next(NULL){};//默認構造函數Node(int value):value(value),next(NULL){};//帶參數的構造函數 ~ Node(){cout<<"delete the node!!!"<<endl;delete next; // 刪除節點的指針域 } 
}; int main(){Node *head , *curr;  //定義頭結點指針和當前插入節點的指針head = new Node();//頭插法生成鏈表 for(int i = 0 ; i < 10 ; i++ ){curr = new Node(i);if(curr==NULL){cerr<<"內存分配失敗!"<<endl; }else{curr->next = head->next;  //將當前節點指針指向之前頭結點指向的地方head->next = curr;  //頭結點指向當前的節點cout<<"the value is : "<<curr->value<<endl;}}return 0;
} 

the value is : 0
the value is : 1
the value is : 2
the value is : 3
the value is : 4
the value is : 5
the value is : 6
the value is : 7
the value is : 8
the value is : 9

那么鏈表該如何遍歷呢,剛開頭的時候就說,遍歷鏈表需要從頭到尾,訪問每一個元素,直到鏈表尾。也就是說不斷地訪問當前節點的next,直到NULL。下面是鏈表的遍歷輸出

#include <iostream>using namespace std;class Node{
public:int value;//鏈表節點的數據域Node* next;//用于指向下一個節點,是鏈表中的指針域Node():value(0),next(NULL){};//默認構造函數Node(int value):value(value),next(NULL){};//帶參數的構造函數 ~ Node(){cout<<"delete the node!!!"<<endl;delete next; // 刪除節點的指針域 } 
}; int main(){Node *head , *curr;head = new Node();//頭插法生成鏈表 for(int i = 0 ; i < 10 ; i++ ){curr = new Node(i);if(curr==NULL){cerr<<"內存分配失敗!"<<endl; }else{curr->next = head->next;head->next = curr;
//			cout<<"the value is : "<<curr->value<<endl;}}//鏈表的遍歷while(head){cout<<"current data is : "<<head->value<<endl;head = head->next;} return 0;
} 

current data is : 0
current data is : 9
current data is : 8
current data is : 7
current data is : 6
current data is : 5
current data is : 4
current data is : 3
current data is : 2
current data is : 1
current data is : 0

3.鏈表的高階使用

鏈表相對于數組有個非常明顯的優點就是能以時間復雜度o(1)完成一個節點的插入或者刪除操作。

插入操作的原理很簡單,假設現在有三個節點,一個是當前節點curr,一個是當前節點的下一個節點,也就是后繼節點,假設為next,還有一個待插入的節點,假設為insert。插入操作就是讓當前節點的后繼節點指向insert節點,insert節點的后繼節點指向next節點。以下是示意圖
在這里插入圖片描述
刪除操作的原理也是類似的,就是讓當前節點的后繼節點指向它后繼節點的后繼節點。示意圖如下

在這里插入圖片描述

那么插入和刪除操作用代碼如何實現呢,我們還用原先的鏈表,先插入一個值為20的節點,輸出鏈表的全部元素。然后再刪除鏈表中這個值為20的元素,輸出元素的全部內容。代碼如下:

#include <iostream>
#include <deque>using namespace std;class Node{
public:int value;//鏈表節點的數據域Node* next;//用于指向下一個節點,是鏈表中的指針域Node():value(0),next(NULL){};//默認構造函數Node(int value):value(value),next(NULL){};//帶參數的構造函數 ~ Node(){cout<<"delete the node!!!"<<endl;delete next; // 刪除節點的指針域 } 
}; int main(){Node *head , *curr;head = new Node();//頭插法生成鏈表 for(int i = 0 ; i < 10 ; i++ ){curr = new Node(i);if(curr==NULL){cerr<<"內存分配失敗!"<<endl; }else{curr->next = head->next;head->next = curr;}}//鏈表的插入curr = head;while(curr->value != 5){   //第一步:找到要插入的節點的前驅 curr = curr->next;}cout<<"curret node is : "<<curr->value<<endl;Node* insertNode = new Node(55);  //創建要插入的節點 insertNode->next = curr->next;  //第二步:將插入的節點的指針域指向當前節點的后繼 curr->next = insertNode;  //第三步:將當前節點的指針指向插入的新節點//鏈表遍歷curr = head;while(curr){cout<<"the value is : "<<curr->value<<endl;curr = curr->next;}//鏈表元素的刪除//第一步找到要刪除的節點的前繼curr = head;while(curr->next->value != 55){curr = curr->next;}cout<<"curret node is : "<<curr->value<<endl;Node *tempNode;tempNode = curr->next;  //第二步:保存下要刪除的節點 curr->next = tempNode->next; //第三步:將要刪除節點的前繼指針指向要刪除節點的后繼 delete tempNode;  //第四步:刪除當前的節點//鏈表遍歷curr = head;while(curr){cout<<"the value is : "<<curr->value<<endl;curr = curr->next;}return 0;
} 

curret node is : 5
the value is : 0
the value is : 9
the value is : 8
the value is : 7
the value is : 6
the value is : 5
the value is : 55
the value is : 4
the value is : 3
the value is : 2
the value is : 1
the value is : 0
curret node is : 5
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
delete the node!!!
the value is : 0
the value is : 9
the value is : 8
the value is : 7
the value is : 6
the value is : 5
the value is : 4
the value is : 3
the value is : 2
the value is : 1
the value is : 0
至于完整的鏈表,STL中有標準的庫,也有功能非常全面的API,只要我們知道內部的實現原理,調用這些API是非常簡單的事,用起來也會得心應手。

4.鏈表的其他操作

// 在末尾加入新的結點
void AddToTail(ListNode** pHead, int value){ListNode* pNew = new ListNode();pNew->val = value;pNew->next = nullptr;if (*pHead == nullptr){*pHead = pNew;}else{ListNode* pNode = *pHead;while(pNode->next != nullptr)pNode = pNode->next;pNode->next = pNew;}return;
}// 刪除某個值為value的結點
void RemoveNode(ListNode** pHead, int value){if(pHead == nullptr || *pHead == nullptr) return;ListNode* pToDeleted = nullptr;if((*pHead)->val == value){pToDeleted = *pHead;*pHead = (*pHead)->next;}else{ListNode* pNode = *pHead;while(pNode->next != nullptr && pNode->next->val != value)pNode = pNode->next;if(pNode->next != nullptr && pNode->next->val == value){pToDeleted = pNode->next;pNode->next = pNode->next->next;}}if(pToDeleted != nullptr){delete pToDeleted;pToDeleted = nullptr;}return;
}

鏈表容器list

1.list介紹

在這里插入圖片描述

2. list使用

在這里插入圖片描述
在這里插入圖片描述

3. list與vector之間的區別

在這里插入圖片描述

4.list例子代碼

#include <iostream>
#include <list>using namespace std;int main(){list<int> c1;list<int>::iterator c1_iter;//向鏈表的末尾加入元素 c1.push_back(1);c1.push_back(2);c1.push_back(3);//使用迭代器訪問鏈表 for(c1_iter = c1.begin();c1_iter != c1.end();c1_iter++){cout<<"data is : "<<*c1_iter<<endl;}//將鏈表反轉 c1.reverse();for(c1_iter = c1.begin();c1_iter != c1.end();c1_iter++){cout<<"reverse data is : "<<*c1_iter<<endl;}return 0;
}

data is : 1
data is : 2
data is : 3
reverse data is : 3
reverse data is : 2
reverse data is : 1

#include <list>  
#include <iostream>  int main( )  
{  using namespace std;  list <int> c1;  list <int>::iterator c1_Iter;  c1.push_back( 20 );  c1.push_back( 10 );  c1.push_back( 30 );  cout << "Before sorting: c1 =";  for ( c1_Iter = c1.begin( ); c1_Iter != c1.end( ); c1_Iter++ )  cout << " " << *c1_Iter;  cout << endl;  c1.sort( );  cout << "After sorting c1 =";  for ( c1_Iter = c1.begin( ); c1_Iter != c1.end( ); c1_Iter++ )  cout << " " << *c1_Iter;  cout << endl;  c1.sort( greater<int>( ) );  cout << "After sorting with 'greater than' operation, c1 =";  for ( c1_Iter = c1.begin( ); c1_Iter != c1.end( ); c1_Iter++ )  cout << " " << *c1_Iter;  cout << endl;  
}

Before sorting: c1 = 20 10 30
After sorting c1 = 10 20 30
After sorting with ‘greater than’ operation, c1 = 30 20 10

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

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

相關文章

論文閱讀 狀態壓縮

狀態壓縮 Abstract 信息學發展勢頭迅猛&#xff0c;信息學奧賽的題目來源遍及各行各業&#xff0c;經常有一些在實際應用中很有價值的問題被引入信息學并得到有效解決。然而有一些問題卻被認為很可能不存在有效的(多項式級的)算法&#xff0c;本文以對幾個例題的剖析&#xf…

數據結構和算法(06)---二叉樹(c++)

文章目錄目錄二叉樹1.二叉樹的基本概念2.二叉樹的應用和時間復雜度3.二叉樹的插入4.二叉樹的查找5. 二叉樹的遍歷6.二叉樹的刪除二叉樹的基本操作1.二叉樹的基礎操作2.代碼實現創建二叉樹和三種遍歷二叉樹的方法目錄 數據結構&#xff1a; 邏輯結構&#xff1a;數組&#xff0c…

如何轉載CSDN博客

前言 對于喜歡逛CSDN的人來說&#xff0c;看別人的博客確實能夠對自己有不小的提高&#xff0c;有時候看到特別好的博客想轉載下載&#xff0c;但是不能一個字一個字的敲了&#xff0c;這時候我們就想快速轉載別人的博客&#xff0c;把別人的博客移到自己的空間里面&#xff0c…

程序員歌曲推薦

更多的時候&#xff0c;不光是電腦和鍵盤陪著我們度過一天&#xff0c;耳機和音樂也成了IT人生活中必不可少的一部分 上班和下班的路上&#xff0c;心情失落時&#xff0c;失眠時&#xff0c;甚至是工作時都可能會聽音樂&#xff0c;讓音樂為我們療傷&#xff0c;讓精神得以放…

如何在博客內添加音樂

<center> <iframe border"0" width"480" height"640" src"//music.163.com/outchain/player?type0&amp;id448977181;auto1&amp;height430"> </iframe> </center> 將代碼復制到markdown編輯器里&am…

CSDN寫博客(字體顏色、大小)

markdown里面的標記語言可以使用標簽對來實現對文本文字顏色大小信息的控制。下面給出幾個實例&#xff1a; 黑體字示例 微軟雅黑示例 華文彩云示例 color#00ffff size可以根據實際大小進行設置&#xff0c;一般不超過7。 紅色字體CSDN 紅色字體CSDN 使用十六進制顏色值 …

bose qc30 安靜的城市是什么樣子

使用感受 網友1&#xff08;20歲&#xff09;&#xff1a; 當你帶著這個耳機聽音樂的時候&#xff0c;有一種感覺&#xff0c;感覺這個世界都是你歌曲里的MV&#xff0c;這個枯燥乏味的世界都被賦予了你心中的那份情感&#xff0c;這種感覺&#xff0c;真的很棒 網友2&#…

DeepLearning.ai 提煉筆記(5-1)-- 循環神經網絡

參考博客 Class 5: 序列模型Sequence Models Week 1: 循環神經網絡RNN (Recurrent) 文章目錄Class 5: 序列模型Sequence ModelsWeek 1: 循環神經網絡RNN (Recurrent)目錄序列模型-循環神經網絡1.序列模型的應用2.數學符號3.循環神經網絡模型傳統標準的神經網絡循環神經網絡的…

常見人工智能比賽平臺總結

目錄1.kaggle比賽1.1 kaggle比賽是什么&#xff1f;1.2 為什么舉辦kaggle比賽&#xff1f;1.3 kaggle比賽形式是什么&#xff1f;1.4 kaggle比賽的獎勵制度是什么&#xff1f;2.阿里天池比賽2.1 阿里天池比賽是什么&#xff1f;2.2 為什么舉辦阿里天池比賽&#xff1f;2.3 阿里…

機器學習模型評分總結(sklearn)

文章目錄目錄模型評估評價指標1.分類評價指標acc、recall、F1、混淆矩陣、分類綜合報告1.準確率方式一&#xff1a;accuracy_score方式二&#xff1a;metrics2.召回率3.F1分數4.混淆矩陣5.分類報告6.kappa scoreROC1.ROC計算2.ROC曲線3.具體實例2.回歸評價指標3.聚類評價指標1.…

kaggle (02) - 房價預測案例(進階版)

房價預測案例&#xff08;進階版&#xff09; 這是進階版的notebook。主要是為了比較幾種模型框架。所以前面的特征工程部分內容&#xff0c;我也并沒有做任何改動&#xff0c;重點都在后面的模型建造section Step 1: 檢視源數據集 import numpy as np import pandas as pd讀…

《Head First設計模式》第二章筆記 觀察者模式

背景 客戶有一個WeatherData對象&#xff0c;負責追蹤溫度、濕度和氣壓等數據。現在客戶給我們提了個需求&#xff0c;讓我們利用WeatherData對象取得數據&#xff0c;并更新三個布告板&#xff1a;目前狀況、氣象統計和天氣預報。 WeatherData對象提供了4個接口&#xff1a; …

libsvm總結

1. 訓練 格式&#xff1a;model libsvmtrain(training_label_vector, training_instance_matrix [, libsvm_options]); 這個函數有三個參數&#xff0c;其中 -training_label_vector:訓練樣本的類標&#xff0c;如果有m個樣本&#xff0c;就是m x 1的矩陣&#xff08;類型必須…

《Head First設計模式》第三章筆記 裝飾者模式

裝飾者模式&#xff08;Decorator Pattern) *利用組合&#xff08;composition&#xff09;和委托&#xff08;delegation&#xff09;可以在運行時實現繼承行為的效果&#xff0c;動態地給對象加上新的行為。 *利用繼承擴展子類的行為&#xff0c;是在編譯時靜態決定的&#x…

機器學習中如何解決數據不平衡問題?

文章目錄目錄什么是數據不平衡問題&#xff1f;數據不平衡會造成什么影響&#xff1f;如何處理數據不平衡問題&#xff1f;1、重新采樣訓練集1.1隨機欠抽樣1.2.基于聚類的過采樣2.使用K-fold交叉驗證3.轉化為一分類問題4.組合不同的重采樣數據集5.用不同比例重新采樣6.多模型Ba…

《Head First設計模式》第四章筆記 工廠模式

之前我們一直在使用new操作符&#xff0c;但是實例化這種行為并不應該總是公開的進行&#xff0c;而且初始化經常會造成耦合問題&#xff0c;工廠模式將擺脫這種復雜的依賴&#xff0c;本次內容包括簡單工廠&#xff0c;工廠方法和抽象工廠三種情況。 1 2 3 4 5 6 Duck duck&a…

《Head First設計模式》第五章筆記-單件模式

單件模式 定義&#xff1a;確保一個類只有一個實例&#xff0c;并提供全局訪問點。 編寫格式&#xff1a; 1 2 3 4 5 6 public class MyClass{ private MyClass(){}//構造方法私有化 public static MyClass getInstance(){ //提供全局訪問點 return new My…

處理機器學習大數據的7種方法

文章目錄目錄1.分配更多的內存2.使用較小的樣本3.將數據提交至服務器上4.更改數據格式5.使用數據流方式或者逐行讀入的方法6.使用關系數據庫7.使用大數據平臺目錄 在實際的生產過程中&#xff0c;我們經常會遇到數據文件太大&#xff0c;而無法直接讀入到計算機中進行處理&…

《Head First設計模式》第六章筆記-命令模式

封裝調用-命令模式 命令模式可將“動作的請求者”從“動作的執行者”對象中解耦。 本篇中將不再描述書中所引入的“巴斯特家電自動化公司”的遙控器控制案例&#xff0c;而使用簡單易懂的餐廳案例。 在開始之前&#xff0c;讓我們通過一個現實中的例子來了解命令模式。 理解…

kaggle(04)---avazu_ctr_predictor(baseline)

比賽的目的&#xff1a; 通過分析網上的系統日志和用戶行為信息&#xff0c;來預測某些網頁上項目的點擊率。是一個二分類的問題&#xff0c;只需要預測出用戶是否點擊即可最好能夠輸出某個概率&#xff0c;比如&#xff1a;用戶點擊某個廣告的概率。 比賽官網 文件信息&…