連結リストを作る (1)
C/C++ の配列は、そのサイズをコンパイル時に決定する必要があります。
そのため、サイズが動的に変化するデータの格納が少々面倒だったりします。
そこでよく用いられるのが、連結リストと呼ばれるデータ構造です。 殆どの環境ではライブラリとして提供されていますが、勉強もかねて自分で実装してみましょう。
そのため、サイズが動的に変化するデータの格納が少々面倒だったりします。
そこでよく用いられるのが、連結リストと呼ばれるデータ構造です。 殆どの環境ではライブラリとして提供されていますが、勉強もかねて自分で実装してみましょう。
設計
コードを書き始めるまえに、簡単な設計を行いましょう。
この段階では詳細には立ち入らず、データの構造をおおまかに決定すれば十分です。(図 1)

【図1: 連結リストの構造】
リストを構成するノード (node) はそれぞれ、自分の前後に位置するノードのアドレスをメンバ変数
リストの本体 (list) は、始端および終端ノードのアドレスを
だいたいの構造が決まったら、いよいよ実装を始めます。
この段階では詳細には立ち入らず、データの構造をおおまかに決定すれば十分です。(図 1)

【図1: 連結リストの構造】
m_lpPrev, m_lpNext に保持します。
(始端ノードの m_lpPrev および、終端ノードの m_lpNext はNULLとする)。リストの本体 (list) は、始端および終端ノードのアドレスを
m_lpHead, m_lpTail として保持します (リストが空の場合は、m_lpHead, m_lpTail は共にNULLとする)。だいたいの構造が決まったら、いよいよ実装を始めます。
ノードの定義
まずは、リストのデータを保持するノード (ListNode クラステンプレート) を定義します。
| ListNode.h |
////////////////////////////////////////////////////////////////////////////////
//
// ListNode.h
//
#ifndef __LISTNODE_H__
#define __LISTNODE_H__
#include <assert.h>
#ifndef NULL
#define NULL 0
#endif
//略記用マクロ
#define LPCNODE const ListNode<T>*
#define LPNODE ListNode<T>*
#define _TEMPLATE template <typename T>
//プロトタイプ宣言
_TEMPLATE class List;
//リストノード
_TEMPLATE class ListNode {
friend class List<T>;
public:
T value; //ノード値
//construction
ListNode(LPNODE lpPrev, LPNODE lpNext, const T& value);
//member access (getting)
LPNODE Prev();
LPCNODE Prev() const;
LPNODE Next();
LPCNODE Next() const;
protected:
LPNODE m_lpPrev; //前ノードのアドレス
LPNODE m_lpNext; //次ノードのアドレス
};
////////////////////////////////////////////////////////////////////////////////
//construction
▼実装部を表示
////////////////////////////////////////////////////////////////////////////////
//member access (getting)
▼実装部を表示
//略記用マクロ解除
#undef LPCNODE
#undef LPNODE
#undef _TEMPLATE
#endif //__LISTNODE_H__
//[EOF] |
m_lpPrev, m_lpNext はユーザに勝手に書き換えられては困るので、protected とし、アクセス用のメンバ関数 Prev, Next を作っておきます。
リストの定義
次に、この連結されたノード列を管理するためのクラス List を作成します。
実際にはここで記述されるもの以外の機能も必要ですが、今回は次節のサンプルコードの動作に最低限必要なものだけを実装します。
実際にはここで記述されるもの以外の機能も必要ですが、今回は次節のサンプルコードの動作に最低限必要なものだけを実装します。
| List.h |
////////////////////////////////////////////////////////////////////////////////
//
// List.h
//
#ifndef __LIST_H__
#define __LIST_H__
#include "ListNode.h"
//略記用マクロ
#define LPCNODE const ListNode<T>*
#define LPNODE ListNode<T>*
#define _TEMPLATE template <typename T>
_TEMPLATE class List {
public:
const int& size;
//construction
List();
List(const List<T>&);
//destruction
virtual ~List();
//operator
List<T>& operator = (const List<T>&);
T& operator [] (int nIndex) ;
const T& operator [] (int nIndex) const;
//operation
LPNODE Append(const T&);
protected:
LPNODE m_lpHead; //始端ノードのアドレス
LPNODE m_lpTail; //終端ノードのアドレス
int m_nSize; //要素数
//operation
LPNODE GetLPNode(int nIndex);
LPCNODE GetLPNode(int nIndex) const;
private:
//destruction
void Destroy();
};
////////////////////////////////////////////////////////////////////////////////
//construction
▼実装部を表示
////////////////////////////////////////////////////////////////////////////////
//destruction
▼実装部を表示
////////////////////////////////////////////////////////////////////////////////
//operator
▼実装部を表示
////////////////////////////////////////////////////////////////////////////////
//operation
▼実装部を表示
//略記用マクロ解除
#undef LPNODE
#undef _TEMPLATE
#endif //__LIST_H__
//[EOF] |
使ってみる
このリストを利用した簡単なプログラムを作成し、動作テストを行います。
このとおり、任意長の長さのデータをメモリ上に読み込むことができます。
次回は、要素の挿入・削除といった動作のためのメンバ関数の作成を行います。
担当: 成田
#include <stdio.h>
#include "List.h"
int main(){
List<char> list;
//読み込み
for (;;){
int n =getc(stdin);
if (n == EOF) break;
list.Append(static_cast<char>(n));
}
//出力
int i;
for (i=0; i<list.size; ++i){
putc(list[i], stdout);
} //i
return 0;
} |
|
Truth is always bitter to those who fear it.[LF] [EOF] Truth is always bitter to those who fear it. |
次回は、要素の挿入・削除といった動作のためのメンバ関数の作成を行います。
担当: 成田

コメント (1)
わかんねーよwwwwwwwwww
バロスwwwwwwwwwwwwwwww
投稿者: ぱ | 2010年07月05日 11:10