1. 程式人生 > >用C++寫一個連結串列

用C++寫一個連結串列

基本資料結構:連結串列(list)

作者:C小加 更新時間:2012-7-31

談到連結串列之前,先說一下線性表。線性表是最基本、最簡單、也是最常用的一種資料結構。線性表中資料元素之間的關係是一對一的關係,即除了第一個和最後一個數據元素之外,其它資料元素都是首尾相接的。線性表有兩種儲存方式,一種是順序儲存結構,另一種是鏈式儲存結構。

順序儲存結構就是兩個相鄰的元素在記憶體中也是相鄰的。這種儲存方式的優點是查詢的時間複雜度為O(1),通過首地址和偏移量就可以直接訪問到某元素,關於查詢的適配演算法很多,最快可以達到O(logn)。缺點是插入和刪除的時間複雜度最壞能達到O(n),如果你在第一個位置插入一個元素,你需要把陣列的每一個元素向後移動一位,如果你在第一個位置刪除一個元素,你需要把陣列的每一個元素向前移動一位。還有一個缺點,就是當你不確定元素的數量時,你開的陣列必須保證能夠放下元素最大數量,遺憾的是如果實際數量比最大數量少很多時,你開的陣列沒有用到的記憶體就只能浪費掉了。

我們常用的陣列就是一種典型的順序儲存結構,如圖1。


鏈式儲存結構就是兩個相鄰的元素在記憶體中可能不是相鄰的,每一個元素都有一個指標域,指標域一般是儲存著到下一個元素的指標。這種儲存方式的優點是插入和刪除的時間複雜度為O(1),不會浪費太多記憶體,新增元素的時候才會申請記憶體,刪除元素會釋放記憶體,。缺點是訪問的時間複雜度最壞為O(n),關於查詢的演算法很少,一般只能遍歷,這樣時間複雜度也是線性(O(n))的了,頻繁的申請和釋放記憶體也會消耗時間。

順序表的特性是隨機讀取,也就是訪問一個元素的時間複雜度是O(1),鏈式表的特性是插入和刪除的時間複雜度為O(1)。要根據實際情況去選取適合自己的儲存結構。

連結串列就是鏈式儲存的線性表。根據指標域的不同,連結串列分為單向連結串列、雙向連結串列、迴圈連結串列等等。

一、 單向連結串列(slist)

連結串列中最簡單的一種是單向連結串列,每個元素包含兩個域,值域和指標域,我們把這樣的元素稱之為節點。每個節點的指標域內有一個指標,指向下一個節點,而最後一個節點則指向一個空值。如圖2就是一個單向連結串列。


一個單向連結串列的節點被分成兩個部分。第一個部分儲存或者顯示關於節點的資訊,第二個部分儲存下一個節點的地址。單向連結串列只可向一個方向遍歷。

我寫了一個簡單的C++版單向連結串列類模板,就用這段程式碼講解一下一個具體的單向連結串列該怎麼寫(程式碼僅供學習),當然首先你要具備C++基礎知識和簡單的模板超程式設計。

完整程式碼

首先我們要寫一個節點類,連結串列中的每一個節點就是一個節點類的物件。如圖3。


程式碼如下:


template<class T>
class slistNode
{
    public:
    slistNode(){next=NULL;}//初始化    T data;//    slistNode* next;//指向下一個節點的指標};

第二步,寫單鏈表類的宣告,包括屬性和方法。

程式碼如下:


template<class T>
class myslist
{
    private:
    unsigned int listlength;
    slistNode<T>* node;//臨時節點    slistNode<T>* lastnode;//頭結點    slistNode<T>* headnode;//尾節點    public:
        myslist();//初始化        unsigned int length();//連結串列元素的個數        void add(T x);//表尾新增元素        void traversal();//遍歷整個連結串列並列印        bool isEmpty();//判斷連結串列是否為空        slistNode<T>* find(T x);//查詢第一個值為x的節點,返回節點的地址,找不到返回NULL        void Delete(T x);//刪除第一個值為x的節點        void insert(T x,slistNode<T>* p);//在p節點後插入值為x的節點        void insertHead(T x);//在連結串列的頭部插入節點};

第三步,寫建構函式,初始化連結串列類的屬性。

程式碼如下:

template<class T>
myslist<T>::myslist()
{
    node=NULL;
    lastnode=NULL;
    headnode=NULL;
    listlength=0;
}

第四步,實現add()方法。

程式碼如下:

template<class T>
void  myslist<T>::add(T x)
{
    node=new slistNode<T>();//申請一個新的節點    node->data=x;//新節點賦值為x    if(lastnode==NULL)//如果沒有尾節點則連結串列為空,node既為頭結點,又是尾節點    {
        headnode=node;
        lastnode=node;
    }
    else//如果連結串列非空    {
        lastnode->next=node;//node既為尾節點的下一個節點        lastnode=node;//node變成了尾節點,把尾節點賦值為node    }
    ++listlength;//元素個數+1}

第五步,實現traversal()函式,遍歷並輸出節點資訊。

程式碼如下:

template<class T>
void  myslist<T>::traversal()
{
    node=headnode;//用臨時節點指向頭結點    while(node!=NULL)//遍歷連結串列並輸出    {
        cout<<node->data<<ends;
        node=node->next;
    }
    cout<<endl;
}

第六步,實現isEmpty()函式,判斷連結串列是否為空,返回真為空,假則不空。

程式碼如下:

template<class T>
bool  myslist<T>::isEmpty()
{
    return listlength==0;
}

第七步,實現find()函式。

程式碼如下:

template<class T>
slistNode<T>* myslist<T>::find(T x)
{
    node=headnode;//用臨時節點指向頭結點    while(node!=NULL&&node->data!=x)//遍歷連結串列,遇到值相同的節點跳出    {
        node=node->next;
    }
    return node;//返回找到的節點的地址,如果沒有找到則返回NULL}

第八步,實現delete()函式,刪除第一個值為x的節點,如圖4。


程式碼如下:

template<class T>
void  myslist<T>::Delete(T x)
{
    slistNode<T>* temp=headnode;//申請一個臨時節點指向頭節點    if(temp==NULL) return;//如果頭節點為空,則該連結串列無元素,直接返回    if(temp->data==x)//如果頭節點的值為要刪除的值,則刪除投節點    {
        headnode=temp->next;//把頭節點指向頭節點的下一個節點        if(temp->next==NULL) lastnode=NULL;//如果連結串列中只有一個節點,刪除之後就沒有節點了,把尾節點置為空        delete(temp);//刪除頭節點        return;
    }
    while(temp->next!=NULL&&temp->next->data!=x)//遍歷連結串列找到第一個值與x相等的節點,temp表示這個節點的上一個節點    {
        temp=temp->next;
    }
    if(temp->next==NULL) return;//如果沒有找到則返回    if(temp->next==lastnode)//如果找到的時候尾節點    {
        lastnode=temp;//把尾節點指向他的上一個節點        delete(temp->next);//刪除尾節點        temp->next=NULL;
    }
    else//如果不是尾節點,如圖4    {
        node=temp->next;//用臨時節點node指向要刪除的節點        temp->next=node->next;//要刪除的節點的上一個節點指向要刪除節點的下一個節點        delete(node);//刪除節點        node=NULL;
    }
}

第九步,實現insert()和insertHead()函式,在p節點後插入值為x的節點。如圖5。



程式碼如下:

template<class T>
void  myslist<T>::insert(T x,slistNode<T>* p)
{
    if(p==NULL) return;
    node=new slistNode<T>();//申請一個新的空間    node->data=x;//如圖5    node->next=p->next;
    p->next=node;
    if(node->next==NULL)//如果node為尾節點    lastnode=node;
}
template<class T>
void  myslist<T>::insertHead(T x)
{
    node=new slistNode<T>();
    node->data=x;
    node->next=headnode;
    headnode=node;
}

相關推薦

C++一個連結串列

基本資料結構:連結串列(list) 作者:C小加 更新時間:2012-7-31 談到連結串列之前,先說一下線性表。線性表是最基本、最簡單、也是最常用的一種資料結構。線性表中資料元素之間的關係是一對一的關係,即除了第一個和最後一個數據元素之外,其它資料元素都是首尾相接的。線性

C#個NBiot串列埠小工具

背景 做嵌入式這行剛剛開始入門基本就是流水燈跟串列埠這些了,一直用別人的工具(在此感謝那些前輩寫的很好用的工具),雖然很好,但是缺少一些定製化的開發。比如最近我在做NBiot的專案,在除錯NB模組的時候就需要手動複製貼上MsgID號碼,十分繁瑣,有時候還會因為超時,不得不從頭來走一遍

C#一個簡單的進度介面

介面設計如下: 實現類: public partial class FormProgressInfo : Form { public FormProgressInfo(int nMinimum = 0, int nMaximum = 100) { InitializeCom

C一個UDP傳送和接收程式

1、UDP網路程式設計主要流程 UDP協議的程式設計框架,客戶端和伺服器之間的差別在於伺服器必須使用bind()函式來繫結偵聽的本地UDP埠,而客戶端則可以不進行繫結,直接傳送到伺服器地址的某個埠地址。框圖如圖1.3所示 UDP協議的伺服器端流程 伺服器流程主要分為下述6個部分,即建立套

【JavaScript】JavaScript實現一個連結串列

append(element) :向列表尾部新增一個新的項。 insert(position, element) :向列表的特定位置插入一個新的項。 indexOf(element) :返回元素在列表中的索引。如果列表中沒有該元素則返回 -1 。 removeA

(一)C++一個紅黑樹/區間樹

lab2 紅黑樹&區間樹(C實現) 本文分為3部分,第一部分實現一棵紅黑樹的左旋/右旋/插入和刪除。 第二部分將第一部分中的紅黑樹擴充套件成一棵區間樹。 第三部分是對區間樹(插入/刪除/搜尋)的測試。 part 1 紅黑樹的插入刪除操作 part 2 區間樹重疊區間查詢

c++一個簡單的打字遊戲

#include <graphics.h>  //圖形介面的標頭檔案 #include <conio.h> #include <time.h>     //隨機數 #include <stdio.h> #include <

c++ 輸入一個連結串列,從尾到頭列印連結串列每個節點的值。

//這個題預設連結串列的頭結點不為空,是有數值的。第一次做的時候,以為/** * struct ListNode { * int val; * struct ListNode *next; * ListNode(int x) :

ROS的學習(十六)C++一個簡單的伺服器(service)和客戶端(client)

      我們將建立一個伺服器節點add_two_ints_server,它將會收到兩個整數,並且返回它們的和。切換目錄到之前建立的beginner_tutorials包下: cd ~/catkin_ws/src/beginner_tutorials      編輯sr

c++實現單向連結串列和雙向連結串列

連結串列是一種非常基礎的資料結構,本身也比較靈活,突破了陣列在一開始就要確定長度的限制,能夠做到隨時使用隨時分配記憶體。同時還有新增,刪除,查詢等功能。 總的來說,連結串列是由幾個模組構成的。 一,單向連結串列 //連結串列基本元素 struct Nod

模板通用連結串列的方法之一

用模板寫通用連結串列方法之一     以前老師要我們用C語言寫通用連結串列,由於是通用嘛,資料的輸入輸出就不一樣,所以得連結串列演算法和資料分離開來.最近學了多型,可以用基類指標指向派生類的方式寫通用連結串列,實現起來更加方便.今天又給我們講了一個另類的模板的方法. //

C# 一個 Redis 資料同步小工具

用 C# 寫一個 Redis 資料同步小工具 Intro 為了實現 redis 的資料遷移而寫的一個小工具,將一個例項中的 redis 資料同步到另外一個例項中。(原本打算找一個已有的工具去做,找了一個 nodejs 的小工具,結果折騰了好久都沒裝上。。。於是就自己寫了這個小工具) 之所以自己寫一個工具而不是

C語言實現在一個連結串列刪除指定的一個或多個元素

#include<stdio.h> #include<stdlib.h> typedef struct node{ int data; struct node *next; }LinkList; //建立一個連結串列  LinkL

一步一步教你從零開始C語言連結串列---構建一個連結串列

為什麼要學習連結串列? 連結串列主要有以下幾大特性: 1、解決陣列無法儲存多種資料型別的問題。 2、解決陣列中,元素個數無法改變的限制(C99的變長陣列,C++也有變長陣列可以實現)。 3、陣列移動元素的過程中,要對元素進行大範圍的移動,很耗時間,效率也不高。

堅持堅持!Java出刪除一個連結串列的倒數第N個節點,並返回頭節點(N總是可達的)

這個題目有個前提條件就是N總是可達的,所以直接省去了一種情況(N不可達時的情況) 思路: 資料結構裡面首先給定兩個指標p和q分別都指向這個連結串列的頭節點,然後若想求出這個連結串列的倒數第N個節點,方法就是先讓p向後挪N個位置,q不動。 因為N總是可達的,所以會有倆種情況,

C 兩個連結串列中資料節點的資料域為一個字母 ,其中L1包含L2,在L1中找出與L2相等的字串,並將其逆置

前面相關操作在這呢,這個函式依託於此 //結構體 typedef struct Node { ElementType data; struct Node * next; } LNode, * LinkNode; //兩個連結串列中資料節點的資料域為一個字母 http

C++連結串列:判斷一個連結串列是否為迴文結構

#include <iostream> #include <string> #include <stack> using namespace std; struct node { int value; nod

一個連結串列插入函式到極致的演算法

這個連結串列結點插入的函式,會自動根據編號大小而有順序的插入其中(從大到小),不用像我的連結串列版課程設計一樣繁瑣的從頭部插入然後再根據編號的大小來排序,可以節省很多的程式碼量。也就是說按某個設定的順序插入,不是像我之前那樣,從首結點插入,然後再給結點排序,繁瑣,這樣更加簡便。 #inc

C++一個基本的文字編輯軟體

這個軟體暫時命名為桌面筆記本。 軟體的核心是基於Windows SDK自己寫的一個文字編輯類,採用了自定義的視窗類。這次沒有采用微軟的EDIT控制元件,也沒有采用其它的文字編輯軟體包。 該軟體採用面向物件的設計方法, 以便於未來功能的完善和擴充套件。但沒有采用MFC, 而是自己寫了一個應用程