No.001-01 拡張リスト・クラスのテンプレート |
C++でリスト構造をいちいち作んのめんどくさい
かといってSTLの<vector>やら<list>もなんか今ひとつ使いづらい
・・・ので簡単リスト化テンプレートで作ってみました。そして公開。
使い方はシンプル | |
XLIST<クラス名> 変数名; | ・・・宣言 |
push(値); | ・・・アイテムをリストに追加 |
pop(n); | ・・・n番目のアイテムをリストから削除 |
変数名[n]; | ・・・配列的にアクセス |
size(); | ・・・現在のアイテム数の取得 |
例えば
#include "xlist.h"; int main(){ XLIST<int> num; // 宣言 num.push(20); // リストに20という値を追加 num.push(21); // リストに21という値を追加 num.push(22); // リストに22という値を追加 num.pop(); // リストから末尾のアイテム(22の値)を削除 printf("%d\n", num[1]); // 画面にリストの2番目の値を出力 return 0; }; |
というコードを書けば画面(MS-DOSプロンプト)には"21"が表示されます
xlist.h |
#ifndef _XLIST_H_ #define _XLIST_H_ #include <stdio> #include <stdlib> //========================================== // リスト型テンプレート //========================================== // 連結アイテム・クラス template <class T> class LIST_ITEM{ public: T t; // ←アイテム本体 LIST_ITEM *next, *before; // ノード LIST_ITEM(){ next=before=NULL; } // コンストラクタ }; //========================================== // XLIST 拡張リスト //========================================== template <class T> class XLIST { private: // メンバ変数 LIST_ITEM<T> *head, *tail; LIST_ITEM<T> *last_use; int last_use_id; int item_length; public : XLIST(); // コンストラクタ ~XLIST(); // デストラクタ push(T t); // アイテム追加 push(T t, int n); // アイテム追加 pop(int n=-1); // 第n番目のアイテム削除 val_pop(T t); // tの値と同じアイテムの削除 // ランダムアクセス LIST_ITEM<T>* get_ptr_abs(int n); LIST_ITEM<T>* get_ptr_rel(LIST_ITEM<T>* pitem, int n); virtual LIST_ITEM<T>* get_ptr(int n); T &operator [](int n); T &last(); del_all(); init(); set_default(T &t); size(); // アイテム数を返す resize(int n); swap(int n1, int n2){ LIST_ITEM<T> *p T tmp_t=*get_ptr(n1); *get_ptr(n1)=*get_ptr(n2); *get_ptr(n2)=tmp_t; return 0; }; roll(int n1, int n2); }; // コンストラクタ template <class T> XLIST<T>::XLIST(){ init(); } // デストラクタ template <class T> XLIST<T>::~XLIST(){ del_all(); delete head; } // 初期化 template <class T> XLIST<T>::init(){ head = new LIST_ITEM<T>; last_use = tail = head; last_use_id = item_length= 0; return 0; } // アイテム数 template <class T> XLIST<T>::size(){ return item_length; } // アイテム数変更 template <class T> XLIST<T>::resize(int n){ if (n<0) n=0; int i, add_size = n - item_length; if (!add_size){ return item_length; } else if (add_size>0){ T t; for(i=0;i<add_size;i++) push(t); return add_size; } else if (add_size<0){ add_size=-add_size; for(i=0;i<add_size;i++) pop(); return -add_size; } return item_length; } // アクセスエラー時の返り値 設定 template <class T> XLIST<T>::set_default(T &t){ head->t = t; return 0; } // 全破棄 template <class T> XLIST<T>::del_all(){ int i, del_len=size()+1; for(i=0;i<del_len;i++) pop(); return 0; } // ====== ランダムアクセス ===================================================== // 演算子 [] template <class T> T& XLIST<T>::operator [](int n){ LIST_ITEM<T> *p=get_ptr(n); return p->t; } // 演算子 [] template <class T> T& XLIST<T>::last(){ return tail->t; } // 相対パスから template <class T> LIST_ITEM<T>* XLIST<T>::get_ptr_rel(LIST_ITEM<T>* pitem, int n){ if (n>0){ for(int i=0;i<n;i++) if (pitem->next) pitem=pitem->next; } else if (n<0){ n=-n; for(int i=0;i<n;i++) if (pitem->before) pitem=pitem->before; } // printf("rel "); return pitem; }; // 絶対パスから template <class T> LIST_ITEM<T>* XLIST<T>::get_ptr_abs(int n){ LIST_ITEM<T> *pitem=head->next; for(int i=0;i<n;i++) if (pitem->next) pitem=pitem->next; return pitem; } // ランダムアクセス総括関数 template <class T> LIST_ITEM<T>* XLIST<T>::get_ptr(int n){ LIST_ITEM<T> *pitem; int i = n-last_use_id, len=size(); if (n>=len || n<0) return head; if (n > abs(i)){ if ((len-n-1) > abs(i)) pitem = get_ptr_rel(last_use, i); else pitem = get_ptr_rel(tail, n-len+1); } else pitem = get_ptr_abs(n); // 先頭からノード検索 if (pitem) { // 最後にアクセスしたアイテム更新 last_use =pitem; last_use_id =n; } return pitem; } // アイテム移動 (第n1番目のアイテムを第n2番目に移動) template <class T> XLIST<T>::roll(int n1, int n2){ if (item_length<=0) return 0; // LISTアイテムなし LIST_ITEM<T> *bef, *nex, *org, *dst; if (n1<0 || n1>=item_length) org=tail; // n1 が範囲外なら末尾を削除 else org = get_ptr(n1); if (n2<0 || n2>=item_length) dst=tail; // n2 が範囲外なら末尾を削除 else dst = get_ptr(n2); if (!org || !dst || org==head || dst==head || org==dst) return 0; // ターゲット・アイテムを一時リストからはずす bef=org->before; nex=org->next; if (bef) bef->next=nex; if (nex) nex->before=bef; // 一時リストからはずしていたターゲット・アイテムを目的位置にセット bef=dst->before; bef->next=org; // ■-□-□ ■の設定 dst->before=org; // □-□-■ ■の設定 org->next=dst; // □-■-□ ■の設定 org->before=bef; // □-■-□ ■の設定 tail = last_use =get_ptr_abs(item_length); last_use_id =item_length-1; return item_length; } // アイテム追加 template <class T> XLIST<T>::push(T t){ LIST_ITEM<T> *old_tail=tail; // 更新前の末尾ポインタ保持 tail->next = new LIST_ITEM<T>; // 末尾アイテムのnextに新リスト作成 tail=tail->next; // 新リストにtailポインタを合わせる tail->t = t; // 新リストにアイテム代入 tail->before=old_tail; item_length++; return item_length; }; // アイテム追加 (挿入型) template <class T> XLIST<T>::push(T t, int n){ if (n>=item_length) return push(t); if (n<=0) n=0; LIST_ITEM<T> *bef_pitem, *nex_pitem, *pitem; bef_pitem=get_ptr(n-1); // 挿入先の前ポインタ取得(確実に存在) nex_pitem=bef_pitem->next; // 挿入先の次ポインタ保持(NULLのときもあり) pitem = new LIST_ITEM<T>; // 末尾アイテムのnextに新リスト作成 pitem->t = t; // 新リストにアイテム代入 pitem->before=bef_pitem; pitem->next=nex_pitem; bef_pitem->next = pitem; if (nex_pitem) nex_pitem->before = pitem; item_length++; last_use =pitem; last_use_id =n; return item_length; }; // アイテム削除 (第n番目のアイテム削除) template <class T> XLIST<T>::pop(int n){ if (item_length<=0) return 0; // LISTアイテムなし LIST_ITEM<T> *del, *bef, *nex; if (n<0 || n>=item_length) del=tail; // n が範囲外なら末尾を削除 else del = get_ptr(n); if (del==head) return 0; bef = del->before; // 削除アイテムの前のノードGET nex = del->next; // 削除アイテムの次のノードGET bef->next=nex; // 前のノードは確実に存在するのでじかに更新 if (nex) { nex->before=bef; // 削除アイテムが末尾なときnexはNULLなので回避 } else tail=bef; delete del; item_length--; last_use =bef; // 最後にアクセスしたアイテム更新(前のノードに代入) last_use_id =n-1; return item_length; } // tの値と同じアイテムの削除 template <class T> XLIST<T>::val_pop(T t){ LIST_ITEM<T> *p; for(int i=0;i<item_length;i++){ p=get_ptr(i); if (p->t==t) { pop(i); return 1; } } return 0; }; #endif // _XLIST_H_ |
●XLIST サンプル |
#include "xlist.h" int main(){ XLIST<int> list; // int型のリストを宣言 list.push(20); // アイテムを追加 list.push(21); list.push(22); list.push(23); list.push(24); list.push(25); list.pop(3); // list[3]をリストから削除 for(int i=0;i<list.size();i++){ printf("list[%d]=%d\n", i, list[i]); // list[i]を表示 } printf("list.size(); %d\n", list.size()); // リストアイテム数を表示 list.del_all(); // アイテムの全削除、ただしメモリは解放しない。 printf("list.del_all();呼び出し \n"); printf("list.size(); %d\n", list.size()); // リストアイテム数を表示 list.resize(4); // アイテムの数を4個にする printf("list.size(); %d\n", list.size()); // リストアイテム数を表示 return 0; } |
実行結果 |
上記ソースは全て自由に改編して使ってかまいませんが必ず自己責任でね。
- | ホームへ | →次へ 001-02 |