順序表和單鏈表的對(duì)比(十二)-創(chuàng)新互聯(lián)

       我們?cè)谥皩W(xué)習(xí)了線性表和單鏈表的相關(guān)特性,本節(jié)博客我們就來看看它們的區(qū)別。首先提出一個(gè)問題:如何判斷某個(gè)數(shù)據(jù)元素是否存在于線性表中?那肯定是直接遍歷一遍了,我們來看看代碼

十余年的烏爾禾網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)整合營銷推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整烏爾禾建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“烏爾禾網(wǎng)站設(shè)計(jì)”,“烏爾禾網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
#include <iostream>
#include "LinkList.h"

using namespace std;
using namespace DTLib;

int main()
{
    LinkList<int> list;

    for(int i=0; i<5; i++)
    {
        list.insert(0, i);
    }

    for(int i=0; i<list.length(); i++)
    {
        if( list.get(i) == 3 )
        {
            cout << list.get(i) << endl;
        }
    }

    return 0;
}

       我們判斷 3 是都存在于當(dāng)前線性表中,如果存在,便輸出??纯摧敵鼋Y(jié)果

順序表和單鏈表的對(duì)比(十二)

       我們看到在查找的時(shí)候還得去手動(dòng)遍歷一遍,感覺很麻煩。那么我們?cè)谥暗膶?shí)現(xiàn)中,少了一個(gè)操作,那便是查找操作find。它可以為線性表(List)增加一個(gè)查找操作,原型為int find(const T& e) const;參數(shù)為帶查找的數(shù)據(jù)元素;返回值:>=0 時(shí),則表示數(shù)據(jù)元素在線性表中第一次出現(xiàn)的位置;為 -1 時(shí),則表示數(shù)據(jù)元素不存在。下面我們看看數(shù)據(jù)元素查找的示例代碼,如下

LinkList<int> list;

for(int i=0; i<5; i++)
{
    list.insert(0, i);
}

cout << list.find(3) << endl;    // ==> 1

       下來我們?cè)?List.h 源碼中添加 find 操作,如下

List.h 源碼

#ifndef LIST_H
#define LIST_H

#include "Object.h"

namespace DTLib
{

template < typename T >
class List : public Object
{
protected:
    List(const List&);
    List& operator= (const List&);
public:
    List() {}
    virtual bool insert(const T& e) = 0;
    virtual bool insert(int i, const T& e) = 0;
    virtual bool remove(int i) = 0;
    virtual bool set(int i, const T& e) = 0;
    virtual bool get(int i, T& e) const = 0;
    virtual int find(const T& e) const = 0;
    virtual int length() const = 0;
    virtual void clear() = 0;
};

SeqList.h 源碼

#ifndef SEQLIST_H
#define SEQLIST_H

#include "List.h"
#include "Exception.h"

namespace DTLib
{

template < typename T >
class SeqList : public List<T>
{
protected:
    T* m_array;
    int m_length;
public:
    bool insert(int i, const T& e)
    {
        bool ret = ((0 <= i)  && (i <= m_length));

        ret = ret &&  (m_length < capacity());

        if( ret )
        {
            for(int p=m_length-1; p>=i; p--)
            {
                m_array[p+1] = m_array[p];
            }

            m_array[i] = e;
            m_length++;
        }

        return ret;
    }

    bool insert(const T& e)
    {
        return insert(m_length, e);
    }

    bool remove(int i)
    {
        bool ret = ((0 <= i) && (i < m_length));

        if( ret )
        {
            for(int p=i; p<m_length-1; p++)
            {
                m_array[p] = m_array[p+1];
            }

            m_length--;
        }

        return ret;
    }

    bool set(int i, const T& e)
    {
        bool ret = ((0 <= i) && (i < m_length));

        if( ret )
        {
            m_array[i] = e;
        }

        return ret;
    }

    bool get(int i, T& e) const
    {
        bool ret = ((0 <= i) && (i < m_length));

        if( ret )
        {
            e = m_array[i];
        }

        return ret;
    }

    int find(const T& e) const  // O(n)
    {
        bool ret = -1;

        for(int i=0; i<m_length; i++)
        {
            if( m_array[i] == e )
            {
                ret = i;
                break;
            }
        }

        return ret;
    }

    int length() const
    {
        return m_length;
    }

    void clear()
    {
        m_length = 0;
    }

    T& operator[] (int i)
    {
        if( (0 <= i) && (i < m_length) )
        {
            return m_array[i];
        }
        else
        {
            THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter i is invalid ...");
        }
    }
    T operator[] (int i) const
    {
        return (const_cast<SeqList<T>&>(*this))[i];
    }

    virtual int capacity() const = 0;
};

}

#endif // SEQLIST_H

LinkList.h 源碼

#ifndef LINKLIST_H
#define LINKLIST_H

#include "List.h"
#include "Exception.h"

namespace DTLib
{

template < typename T >
class LinkList : public List<T>
{
protected:
    struct Node : public Object
    {
        T value;
        Node* next;
    };

    mutable struct : public Object
    {
        char reserved[sizeof(T)];
        Node* next;
    } m_header;
    int m_length;

    Node* position(int i) const
    {
        Node* ret = reinterpret_cast<Node*>(&m_header);

        for(int p=0; p<i; p++)
        {
            ret = ret->next;
        }

        return ret;
    }
public:
    LinkList()
    {
        m_header.next = NULL;
        m_length = 0;
    }
    bool insert(const T& e)
    {
        return insert(m_length, e);
    }

    bool insert(int i, const T& e)
    {
        bool ret = ((0 <= i) && (i <= m_length));

        if( ret )
        {
            Node* node = new Node();

            if( node != NULL )
            {
                Node* current = position(i);

                node->value = e;
                node->next = current->next;
                current->next = node;

                m_length++;
            }
            else
            {
                THROW_EXCEPTION(NoEnoughMemoryException, "No memory to insert new element ...");
            }
        }
    }

    bool remove(int i)
    {
        bool ret = ((0 <= i) && (i < m_length));

        if( ret )
        {
            Node* current = position(i);
            Node* toDel = current->next;

            current->next = toDel->next;

            delete toDel;

            m_length--;
        }

        return ret;
    }

    bool set(int i, const T& e)
    {
        bool ret = ((0 <= i) && (i < m_length));

        if( ret )
        {
            position(i)->next->value = e;
        }

        return ret;
    }

    T get(int i) const
    {
        T ret;

        if( get(i, ret) )
        {
            return ret;
        }
        else
        {
            THROW_EXCEPTION(IndexOutOfBoundsException, "Invaild parameter i to get element ...");
        }
    }

    bool get(int i, T& e) const
    {
        bool ret = ((0 <= i) && (i < m_length));

        if( ret )
        {
            e = position(i)->next->value;
        }

        return ret;
    }

    int find(const T& e) const
    {
        int ret = -1;
        int i = 0;
        Node* node = m_header.next;

        while( node )
        {
            if( node->value == e )
            {
                ret = i;
                break;
            }
            else
            {
                node = node->next;
                i++;
            }
        }

        return ret;
    }

    int length() const
    {
        return m_length;
    }

    void clear()
    {
        while( m_header.next )
        {
            Node* toDel = m_header.next;

            m_header.next = toDel->next;

            delete toDel;
        }

        m_length = 0;
    }

    ~LinkList()
    {
        clear();
    }
};

}

#endif // LINKLIST_H

       那么此時(shí)的 main.cpp 就可以寫成這樣的了

#include <iostream>
#include "LinkList.h"

using namespace std;
using namespace DTLib;

int main()
{
    LinkList<int> list;

    for(int i=0; i<5; i++)
    {
        list.insert(0, i);
    }

    cout << list.find(3) << endl;

    return 0;
}

       我們來看看結(jié)果

順序表和單鏈表的對(duì)比(十二)

       我們來查找下 -3 呢

順序表和單鏈表的對(duì)比(十二)

       我們看到如果查找的元素在里面,則返回 1;如果沒有,則返回 -1。那么我們?nèi)绻檎业氖穷惸??那程序還會(huì)編譯通過嗎?我們來看看,main.cpp 源碼如下

#include <iostream>
#include "LinkList.h"

using namespace std;
using namespace DTLib;

class Test
{
    int i;
public:
    Test(int v = 0)
    {
        i = v;
    }
};

int main()
{
    Test t1(1);
    Test t2(3);
    Test t3(3);
    LinkList<Test> list;

    return 0;
}

       編譯結(jié)果如下

順序表和單鏈表的對(duì)比(十二)

       編譯報(bào)錯(cuò)了,我們并沒有改動(dòng) LinkList 中的代碼,為什么這塊會(huì)報(bào)錯(cuò)呢?那么此時(shí)我們想要讓兩個(gè)類對(duì)象進(jìn)行相等的比較,可是我們并沒有定義== 操作符,此時(shí)肯定會(huì)出錯(cuò)。那么我們?cè)陬?Test 中進(jìn)行 == 操作符的定義,如下

class Test
{
    int i;
public:
    Test(int v = 0)
    {
        i = v;
    }
    
    bool operator == (const Test& obj)
    {
        return true;
    }
};

       我們?cè)賮砭幾g下,看看結(jié)果

順序表和單鏈表的對(duì)比(十二)

       編譯是通過的,那么我們此時(shí)便覺得奇怪了。我們?yōu)槭裁匆?Test 類中定義 == 操作符呢,此時(shí)最好的解決辦法是在頂層父類 Object 中添加 == 和 != 操作符,然后將 Test 類繼承自 Object 類就可以了。

Object.h 源碼

#ifndef OBJECT_H
#define OBJECT_H

namespace DTLib
{

class Object
{
public:
    void* operator new (unsigned int size) throw();
    void operator delete (void* p);
    void* operator new[] (unsigned int size) throw();
    void operator delete[] (void* p);
    bool operator == (const Object& obj);
    bool operator != (const Object& obj);
    virtual ~Object() = 0;
};

}

#endif // OBJECT_H

Object.cpp 源碼

#include "Object.h"
#include <cstdlib>

namespace DTLib
{

void* Object::operator new (unsigned int size) throw()
{
    return malloc(size);
}

void Object::operator delete (void* p)
{
    free(p);
}

void* Object::operator new[] (unsigned int size) throw()
{
    return malloc(sizeof(size));
}

void Object::operator delete[] (void* p)
{
    free(p);
}

bool Object::operator == (const Object& obj)
{
    return (this == &obj);
}

bool Object::operator != (const Object& obj)
{
    return (this != &obj);
}

Object::~Object()
{

}

}

       此時(shí)的 main.cpp 代碼如下

#include <iostream>
#include "LinkList.h"

using namespace std;
using namespace DTLib;

class Test : public Object
{
    int i;
public:
    Test(int v = 0)
    {
        i = v;
    }

    bool operator == (const Test& obj)
    {
        return (i == obj.i);
    }
};

int main()
{
    Test t1(1);
    Test t2(3);
    Test t3(3);
    LinkList<Test> list;

    list.insert(t1);
    list.insert(t2);
    list.insert(t3);

    cout << list.find(t2) << endl;

    return 0;
}

       我們來看看編譯輸出結(jié)果

順序表和單鏈表的對(duì)比(十二)

       那么我們?cè)?main.cpp 測試代碼中將 t1, t2, t3 對(duì)象插入到 list 中,然后查找 t2 是否存在,那么它肯定是存在的,因此會(huì)輸出 1。那么我們來分析下順序表和單鏈表的時(shí)間復(fù)雜度的對(duì)比,如下

順序表和單鏈表的對(duì)比(十二)

       我們看到順序表只有三個(gè) O(n) ,而單鏈表幾乎是全部是 O(n)。從時(shí)間復(fù)雜度上來看,似乎順序表更占優(yōu)勢(shì),那么我們?cè)谄綍r(shí)的開發(fā)中,為什么經(jīng)常見到的是單鏈表而不是順序表呢?在實(shí)際的工程開發(fā)中,時(shí)間復(fù)雜度只是一個(gè)參考指標(biāo),對(duì)于內(nèi)置基礎(chǔ)類型,順序表和單鏈表的效率不相上下,而對(duì)于自定義類型來說,順序表在效率上低于單鏈表。在插入和刪除操作中,順序表涉及大量數(shù)據(jù)對(duì)象的復(fù)制操作,而單鏈表只涉及指針操作,效率與數(shù)據(jù)對(duì)象無關(guān)。對(duì)于數(shù)據(jù)訪問,順序表是隨機(jī)訪問,可直接定位數(shù)據(jù)對(duì)象;而對(duì)于單鏈表來說是順序訪問,必須從頭訪問數(shù)據(jù)對(duì)象,無法直接定位。

       一般在工程開發(fā)中,順序表主要用于:數(shù)據(jù)元素類型相對(duì)簡單,不涉及深拷貝;數(shù)據(jù)元素相對(duì)穩(wěn)定,訪問操作遠(yuǎn)多于插入和刪除操作。單鏈表主要用于:數(shù)據(jù)元素的類型相對(duì)復(fù)雜,復(fù)制操作相對(duì)耗時(shí);數(shù)據(jù)元素不穩(wěn)定,需要經(jīng)常插入和刪除,訪問操作較少的情況。通過今天的學(xué)習(xí),總結(jié)如下:1、線性表中元素的查找依賴于相等比較操作符(==);2、順序表適用于訪問需求量較大的場合(隨機(jī)訪問);3、單鏈表適用于數(shù)據(jù)元素頻繁插入刪除的場合(順序訪問);4、當(dāng)數(shù)據(jù)類型相對(duì)簡單時(shí),順序表和單鏈表的效率不相上下。

分享文章:順序表和單鏈表的對(duì)比(十二)-創(chuàng)新互聯(lián)
分享鏈接:http://muchs.cn/article44/dsijee.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、App設(shè)計(jì)、網(wǎng)站內(nèi)鏈網(wǎng)站建設(shè)、動(dòng)態(tài)網(wǎng)站、企業(yè)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計(jì)