亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

技巧:在C/C++中如何構造通用的對象鏈表

2019-11-17 05:15:27
字體:
來源:轉載
供稿:網友

  虛擬鏈表和類鏈表可以很好地實現這一點

T. W. Burger
Thomas Wolfgang Burger Consulting公司的老板
2000 年 9 月
內容:
簡化的問題
C 代碼解決方案
C++ 解決方案
小結
參考資源
作者簡介


您是否做過這樣一個項目,它要求您在內存中保存數目不定的若干不同對象?對于某些情況,二叉樹是最佳選擇,但在通常情況下,更簡單的鏈表是顯而易見的選擇。

一個簡化的問題示例
鏈表的難點在于必須復制鏈表處理函數來處理不同的對象,即便邏輯是完全相同的。例如:

兩個結構類似的鏈表

strUCt Struct_Object_A
{
int a;
int b;
Struct_Object_A *next;

} OBJECT_A;

typedef struct Struct_Object_B
{
int a;
int b;
int c;
Struct_Object_B *next;

} OBJECT_B;

上面定義的兩個結構只有很小的一點差別。OBJECT_B 和 OBJECT_A 之間只差一個整型變量。但是,在編譯器看來,它們仍然是非常不同的。必須為存儲在鏈表中的每個對象復制用來添加、刪除和搜索鏈表的函數。為了解決這個問題,可以使用具有全部三個變量的一個聯合或結構,其中整數 c 并不是在所有的情況下都要使用。這可能變得非常復雜,并會形成不良的編程風格。

C 代碼解決方案:虛擬鏈表
此問題更好的解決方案之一是虛擬鏈表。虛擬鏈表是只包含鏈表指針的鏈表。對象存儲在鏈表結構背后。這一點是這樣實現的,首先為鏈表節點分配內存,接著為對象分配內存,然后將這塊內存分配給鏈表節點指針,如下所示:

虛擬鏈表結構的一種實現

typedef struct liststruct
{
liststruct *next;

} LIST, *pLIST;


pLIST Head = NULL;

pLIST AddToList( pLIST Head, void * data, size_t datasize )
{
pLIST newlist=NULL;
void *p;


// 分配節點內存和數據內存
newlist = (pLIST) malloc( datasize + sizeof( LIST ) );

// 為這塊數據緩沖區指定一個指針
p = (void *)( newlist + 1 );

// 復制數據
memcpy( p, data, datasize );

// 將這個節點指定給鏈表的表頭
if( Head )
{
newlist->next = Head;
}
else
newlist->next = NULL;

Head = newlist;

return Head;
}

鏈表節點現在建立在數據值副本的基本之上。這個版本能很好地處理標量值,但不能處理帶有用 malloc 或 new 分配的元素的對象。要處理這些對象,LIST 結構需要包含一個一般的解除函數指針,這個指針可用來在將節點從鏈表中刪除并解除它之前釋放內存(或者關閉文件,或者調用關閉方法)。

一個帶有解除函數的鏈表

typedef void (*ListNodeDestructor)( void * );

typedef struct liststruct
{
ListNodeDestructor DestructFunc;
liststruct *next;

} LIST, *pLIST;

pLIST AddToList( pLIST Head, void * data, size_t datasize,
ListNodeDestructor Destructor )
{
pLIST newlist=NULL;
void *p;


// 分配節點內存和數據內存
newlist = (pLIST) malloc( datasize + sizeof( LIST ) );

// 為這塊數據緩沖區指定一個指針
p = (void *)( newlist + 1 );


// 復制數據
memcpy( p, data, datasize );

newlist->DestructFunc = Destructor;

// 將這個節點指定給鏈表的表頭
if( Head )
{
newlist->next = Head;
}
else
newlist->next = NULL;

Head = newlist;

return Head;
}

void DeleteList( pLIST Head )
{
pLIST Next;
while( Head )
{
Next = Head->next;
Head->DestructFunc( (void *) Head );
free( Head );
Head = Next;
}
}

typedef struct ListDataStruct
{
LPSTR p;

} LIST_DATA, *pLIST_DATA;

void ListDataDestructor( void *p )
{
// 對節點指針進行類型轉換
pLIST pl = (pLIST)p;

// 對數據指針進行類型轉換
pLIST_DATA pLD = (pLIST_DATA) ( pl + 1 );

delete pLD->p;
}
pLIST Head = NULL;

void TestList()
{
pLIST_DATA d = new LIST_DATA;
d->p = new char[24];
strcpy( d->p, "Hello" );
Head = AddToList( Head, (void *) d, sizeof( pLIST_DATA ),
ListDataDestructor );
// 該對象已被復制,現在刪除原來的對象
delete d;

d = new LIST_DATA;
d->p = new char[24];
strcpy( d->p, "World" );
Head = AddToList( Head, (void *) d, sizeof( pLIST_DATA ),
ListDataDestructor );
delete d;

// 釋放鏈表
DeleteList( Head );
}



在每個鏈表節點中包含同一個解除函數的同一個指針似乎是浪費內存空間。確實如此,但只有鏈表始終包含相同的對象才屬于這種情況。按這種方式編寫鏈表答應您將任何對象放在鏈表中的任何位置。大多數鏈表函數要求對象總是相同的類型或類。虛擬鏈表則無此要求。它所需要的只是將對象彼此區分開的一種方法。要實現這一點,您既可以檢測解除函數指針的值,也可以在鏈表中所用的全部結構前添加一個類型值并對它進行檢測。當然,假如要將鏈表編寫為一個 C++ 類,則對指向解除函數的指針的設置和存儲只能進行一次。

C++ 解決方案:類鏈表
本解決方案將 CList 類定義為從 LIST 結構導出的一個類,它通過存儲解除函數的單個值來處理單個存儲類型。請注重添加的 GetCurrentData() 函數,該函數完成從鏈表節點指針到數據偏移指針的數學轉換。

一個虛擬鏈表對象

// 定義解除函數指針

typedef void (*ListNodeDestructor)( void * );

// 未添加解除函數指針的鏈表

typedef struct ndliststruct
{
ndliststruct *next;

} ND_LIST, *pND_LIST;

// 定義處理一種數據類型的鏈表類

class CList : public ND_LIST
{
public:
CList(ListNodeDestructor);
~CList();
pND_LIST AddToList( void * data, size_t datasize );
void *GetCurrentData();
void DeleteList( pND_LIST Head );


PRivate:
pND_LIST m_HeadOfList;
pND_LIST m_CurrentNode;
ListNodeDestructor m_DestructFunc;
};

// 用正確的起始值構造這個鏈表對象

CList::CList(ListNodeDestructor Destructor)
: m_HeadOfList(NULL), m_CurrentNode(NULL)
{
m_DestructFunc = Destructor;

}

// 在解除對象以后刪除鏈表

CList::~CList()
{
DeleteList(m_HeadOfList);
}

// 向鏈表中添加一個新節點

pND_LIST CList::AddToList( void * data, size_t datasize )
{
pND_LIST newlist=NULL;
void *p;


// 分配節點內存和數據內存
newlist = (pND_LIST) malloc( datasize + sizeof( ND_LIST ) );

// 為這塊數據緩沖區指定一個指針
p = (void *)( newlist + 1 );

// 復制數據
memcpy( p, data, datasize );

// 將這個節點指定給鏈表的表頭
if( m_HeadOfList )
{
newlist->next = m_HeadOfList;
}
else
newlist->next = NULL;

m_HeadOfList = newlist;

return m_HeadOfList;
}

// 將當前的節點數據作為 void 類型返回,以便調用函數能夠將它轉換為任何類型

void * CList::GetCurrentData()
{
return (void *)(m_CurrentNode+1);
}

// 刪除已分配的鏈表

void CList::DeleteList( pND_LIST Head )
{
pND_LIST Next;
while( Head )
{
Next = Head->next;
m_DestructFunc( (void *) Head );
free( Head );
Head = Next;
}
}

// 創建一個要在鏈表中創建和存儲的結構

typedef struct ListDataStruct
{
LPSTR p;

} LIST_DATA, *pND_LIST_DATA;

// 定義標準解除函數

void ClassListDataDestructor( void *p )
{
// 對節點指針進行類型轉換
pND_LIST pl = (pND_LIST)p;

// 對數據指針進行類型轉換
pND_LIST_DATA pLD = (pND_LIST_DATA) ( pl + 1 );

delete pLD->p;
}

// 測試上面的代碼

void MyCListClassTest()
{
// 創建鏈表類

CList* pA_List_of_Data = new CList(ClassListDataDestructor);

// 創建數據對象

pND_LIST_DATA d = new LIST_DATA;
d->p = new char[24];
strcpy( d->p, "Hello" );

// 創建指向鏈表頂部的局部指針

pND_LIST Head = NULL;

//向鏈表中添加一些數據

Head = pA_List_of_Data->AddToList( (void *) d,
sizeof( pND_LIST_DATA ) );
// 該對象已被復制,現在刪除原來的對象
delete d;

// 確認它已被存儲
char * p = ((pND_LIST_DATA) pA_List_of_Data->GetCurrentData())->p;

d = new LIST_DATA;
d->p = new char[24];
strcpy( d->p, "World" );
Head = pA_List_of_Data->AddToList( (void *) d, sizeof( pND_LIST_DATA ) );
// 該對象已被復制,現在刪除原來的對象
delete d;

// 確認它已被存儲
p = ((pND_LIST_DATA) pA_List_of_Data->GetCurrentData())->p;

// 刪除鏈表類,析構函數將刪除鏈表
delete pA_List_of_Data;
}



小結
從前面的討論來看,似乎僅編寫一個簡單的鏈表就要做大量的工作,但這只須進行一次。很輕易將這段代碼擴充為一個處理排序、搜索以及各種其他任務的 C++ 類,并且這個類可以處理任何數據對象或類(在一個項目中,它處理大約二十個不同的對象)。您永遠不必重新編寫這段代碼。


參考資源

* The linux C Programming Lists 旨在幫助人們用 C 語言進行 Linux 編程,其中包括許多到郵件列表、常見問題解答、教程以及其他內容的鏈接。
* Microsoft Foundation Class 在其 CList 類中提供了類似的功能。MFC 中的 CList 以及別的類要求類型或類只能是一種類型,程序員對代碼沒有控制權,這一點與從零開始構建鏈表不同。

作者簡介
Thomas Wolfgang Burger 是 Thomas Wolfgang Burger Consulting 公司的老板。自 1978 年以來,他做過咨詢人員、教師、分析員和應用程序開發員??梢酝ㄟ^ twburger@bigfoot.com 與他聯系。

您對這篇文章的看法如何?

真棒! 好文章 一般,尚可 需提高 太差!

意見


(c) Copyright IBM Corp. 2001, (c) Copyright IBM China 2001, All Right Reserved
隱私 法律 聯系

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧洲美女免费图片一区| 国产69精品久久久久9| 亚洲欧美日本另类| 日本精品久久久| 最近2019中文字幕在线高清| 91亚洲精品一区二区| 伊人亚洲福利一区二区三区| 中文字幕一区二区三区电影| 麻豆国产va免费精品高清在线| 国产在线不卡精品| 亚洲欧美国产精品va在线观看| 欧美极品在线视频| 精品亚洲永久免费精品| 久久中文字幕国产| 久久精品视频一| 欧美另类69精品久久久久9999| 在线观看不卡av| 久久99国产综合精品女同| 97超级碰碰人国产在线观看| 国产精品91久久久| 亚洲人成五月天| 欧美另类精品xxxx孕妇| 国产91亚洲精品| 久久国产加勒比精品无码| 在线日韩日本国产亚洲| 中文在线资源观看视频网站免费不卡| 亚洲专区在线视频| 在线观看国产精品91| 亚洲欧洲第一视频| 亚洲男人天天操| 欧美最猛性xxxxx亚洲精品| 91精品久久久久久久| 影音先锋欧美精品| 久久久久久久999精品视频| 久色乳综合思思在线视频| 亚洲2020天天堂在线观看| 亚洲成人av资源网| 91大神在线播放精品| 国产精品免费电影| 日韩精品视频在线观看网址| 欧美劲爆第一页| 8x海外华人永久免费日韩内陆视频| 国产成人a亚洲精品| 综合网日日天干夜夜久久| 国产精品视频自在线| 精品亚洲永久免费精品| 亚洲精品有码在线| 色99之美女主播在线视频| xxx一区二区| 亚洲第一区在线观看| 亚洲缚视频在线观看| 91国产精品91| 狠狠操狠狠色综合网| 欧美性色视频在线| 国产精品专区第二| 国产一区二区动漫| 成人国内精品久久久久一区| 欧美精品性视频| 97超视频免费观看| 国产精品久久久久久影视| 精品久久久久久久久中文字幕| 亚洲一区999| 国产日韩精品入口| 久久激情视频久久| 国语自产偷拍精品视频偷| 国产精品美女网站| 中文字幕日韩av综合精品| 欧美另类精品xxxx孕妇| 91国产高清在线| 日韩电影免费在线观看中文字幕| 精品国产区一区二区三区在线观看| 国产精品扒开腿做爽爽爽男男| 国产成人在线精品| 日韩av在线网站| 久久精品国产清自在天天线| 日本在线精品视频| 精品久久久久久久久久久| 国产欧美日韩综合精品| 97国产精品视频人人做人人爱| 亚洲欧美中文日韩在线| 国产一区二区三区在线观看网站| 91日本在线观看| 精品久久久久久中文字幕一区奶水| 成人日韩在线电影| 久久亚洲精品小早川怜子66| 欧美日韩精品在线| 久久久久久久久久久国产| 久久97久久97精品免视看| 超碰97人人做人人爱少妇| 久久伊人91精品综合网站| 久久久久久久一区二区| 91在线视频导航| 欧美成人午夜激情| 中文字幕国产亚洲2019| 日韩av电影国产| 日韩av中文在线| 91免费国产视频| 国产成人亚洲综合青青| 亚洲精品久久7777777| 夜色77av精品影院| 日韩欧美国产一区二区| 国产精品综合网站| 国产欧洲精品视频| 国产一区二区黑人欧美xxxx| 国产女人18毛片水18精品| 亚洲欧美日韩天堂一区二区| 国产美女久久久| 欧美视频裸体精品| 欧美一级在线播放| 欧美在线免费看| 亚洲色图av在线| 欧美激情精品久久久久久大尺度| 欧美日本在线视频中文字字幕| 国产网站欧美日韩免费精品在线观看| 久久99亚洲热视| 亚洲国产精品字幕| 狠狠色噜噜狠狠狠狠97| 国产精品一区二区久久国产| 国产在线999| 91免费看国产| 国产91在线高潮白浆在线观看| 久久国产精品久久国产精品| 国产精品成人va在线观看| 久久久国产精品x99av| 亚洲无限乱码一二三四麻| 亚洲国产成人爱av在线播放| 国产精品色视频| 日韩电影免费在线观看中文字幕| 国产午夜精品麻豆| 97国产精品视频| 亚洲成人激情图| 日本久久久久久久| 亚洲自拍偷拍第一页| 97高清免费视频| 午夜精品久久17c| 日韩久久免费视频| 国产精品日韩在线一区| 欧美在线性爱视频| 亚洲成色777777女色窝| 亚洲大胆人体视频| 久久香蕉国产线看观看网| 国产精品久久久久久久av电影| 色噜噜狠狠色综合网图区| 欧美制服第一页| 欧美在线视频在线播放完整版免费观看| 久久国内精品一国内精品| 久久久精品视频成人| 欧美日韩精品二区| 久久久久久久久久久免费精品| 亚洲v日韩v综合v精品v| 国产精品永久在线| 久久久影视精品| 欧美成人午夜激情| 97av在线视频| 亚洲精品视频久久| 91精品视频在线| 久久亚洲国产精品成人av秋霞| 国产精品三级美女白浆呻吟| 成人黄色生活片| 97久久精品人搡人人玩| 亚洲缚视频在线观看| 91亚洲永久免费精品| 欧美成人精品在线播放| 欧美另类第一页|