No.001-まとめ 拡張リスト・クラスのテンプレート(総合) |
長所 | 短所 | |
XLIST | ・シンプルにリスト化 ・定数をそのままリスト化できる |
・強制的にデストラクタが発生する。 ・高速push、popは無理 |
PLIST | ・デストラクタの発生が制限できる。 ・ポインタ管理なのでXLISTより速い。 |
・定数をナマでリスト化はできない。必ずポインタ使用。 ・高速push、popは無理 |
QLIST | ・メモリの再利用により高速push、popが可能。 | ・メモリをどこで解放するかがユーザの負担になる。 |
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番目のアイテム削除 // ランダムアクセス 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; // n が範囲外なら末尾を削除 else org = get_ptr(n1); if (n2<0 || n2>=item_length) dst=tail; // n が範囲外なら末尾を削除 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; } // アイテム削除 (第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; } // アイテム追加 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; }; #endif // _XLIST_H_ |
plist.h |
#ifndef _PLIST_H_ #define _PLIST_H_ #include <stdio.h> #include <stdlib.h> #include "xlist.h" //========================================== // PLIST ポインタ・リスト //========================================== template <class T> class PLIST { char destruct_flag; XLIST<T*> xlist; // has a型(多態push作成のためis aでない) public : // n1番目とn2番目のアイテムを交換する(swap) swap(int n1, int n2){ T* tmp_t=xlist[n1]; xlist[n1]=xlist[n2]; xlist[n2]=tmp_t; }; // 最後のアイテム(参照)を返す T* &last(){ return xlist.last(); }; // アイテム数を返す(len, size で同じもの) len(){ return xlist.size(); }; size(){ return xlist.size(); }; // リサイズ resize(int n){ int old_size=size(); // 旧サイズの保持 int res=xlist.resize(n); // メンバxlistでリサイズ実行 int i; if (old_size<size()){ for(i=old_size;i<size();i++) xlist[i]=a_push(); // 追加した分だけメモリ確保 } return res; }; // pop時アイテムのdeleteしないよう設定する set_no_destruct(){ return destruct_flag=0; } // コンストラクタ PLIST(){ destruct_flag=1; // pop時アイテムのdelete(アイテムのデストラクタが走る) T *t=NULL; // デフォルト値はNULL xlist.set_default(t); // デフォルト値はNULLであることをxlistに設定 }; // デストラクタ ~PLIST(){ del_all(); }; // オート・プッシュ T *a_push(int n=-1){ T* pt = new T; if (n==-1) xlist.push(pt); // n==-1ならアイテムは末尾に追加 else xlist.push(pt, n); // n が範囲内ならアイテムはn番目に挿入 // 返り値 return (n==-1)? last() : xlist[n]; } // アイテム追加(通常プッシュ) // 引数 t : 値、 n : 挿入位置 T *push(T &t, int n=-1){ T* pt = new T; *pt=t; if (n==-1) xlist.push(pt); // n==-1ならアイテムは末尾に追加 else xlist.push(pt, n); // n が範囲内ならアイテムはn番目に挿入 // 返り値 return (n==-1)? last() : xlist[n]; } // ポインタ引数でアイテム追加 // 引数 t : 値、 n : 挿入位置 p_push(T *t=NULL, int n=-1){ if (!t) t = new T; if (n==-1) xlist.push(t); else xlist.push(t, n); return 0; }; // 第n番目のアイテム削除 pop(int n=-1){ if (destruct_flag) delete xlist[n]; xlist[n]=NULL; xlist.pop(n); return 0; }; // tの値と同じアイテムの削除 val_pop(T *t){ return xlist.val_pop(t); } // ランダムアクセス T* &operator [](int n){ return xlist[n]; }; // 第n1番目のアイテムを第n2番目に移動 roll(int n1, int n2){ return xlist.roll(n1, n2); } // 全アイテム削除 del_all(){ int i, del_len=xlist.size(); for(i=del_len-1;i>=0;i--) pop(i); return 0; } }; #endif // _PLIST_H_ |
qlist.h |
#ifndef _QLIST_H_ #define _QLIST_H_ #include <stdio> #include <stdlib> #include "plist.h" //========================================== // QLIST クイック・リスト //========================================== template <class T> class QLIST { public : int pret_size; PLIST<T> plist; // has a型(多態push作成のためis aでない) swap(int n1, int n2){ plist.swap(n1, n2); }; T* &last(){ return plist.last(); }; size() { return pret_size; }; // アイテム数を返す mem_size() { return plist.size(); }; // メモリ・アイテム数を返す resize(int n){ if (n>plist.size()) plist.resize(n); // 追加 return pret_size=n; }; mem_resize(int n){ return plist.resize(n); }; T *a_push(int n=-1){ // オート・プッシュ if (n<0 || n>pret_size) n=pret_size; if (pret_size>=plist.size()) plist.a_push(n); else if (n>=0 && n<pret_size) { plist.roll(pret_size, n); // *(plist[n])=t; // 通常プッシュ } pret_size++; return plist[n]; } pop(int n=-1){ if (pret_size<=0) return 0; if (n>0) plist.roll(n, pret_size); pret_size--; } mem_pop(int n=-1){ return plist.pop(n); } // ランダムアクセス T* &operator [](int n){ if (pret_size<=n) return plist[-1]; return plist[n]; }; // コンストラクタ QLIST(){ pret_size=0; }; del_all(){ pret_size=0; } mem_del_all(){ pret_size=0; plist.del_all(); } }; #endif // _QLIST_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; } |
●PLIST サンプル | 実行結果![]() |
#include "plist.h" int main(){ PLIST<int> list; // int型のポインタ・リストを宣言 int n=100, *pn; pn=list.a_push(); // アイテムを追加しそのアイテムへのポインタを得る *pn=n++; // 追加したアイテムに値を代入 pn=list.a_push();*pn=n++; pn=list.a_push();*pn=n++; pn=list.a_push();*pn=n++; pn=list.a_push();*pn=n++; pn=list.a_push();*pn=n++; 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; } |
●QLIST サンプル | 実行結果![]() |
#include "qlist.h" int main(){ QLIST<int> list; // int型のクイック・リストを宣言 int n=100, *pn; pn=list.a_push(); // アイテムを追加しそのアイテムへのポインタを得る *pn=n++; // 追加したアイテムに値を代入 pn=list.a_push();*pn=n++; pn=list.a_push();*pn=n++; pn=list.a_push();*pn=n++; pn=list.a_push();*pn=n++; pn=list.a_push();*pn=n++; 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()); // リストアイテム数を表示 printf("list.mem_size(); %d\n", list.mem_size()); // リストアイテムの現在のメモリ確保数を表示 list.mem_del_all(); printf("list.mem_del_all();呼び出し \n"); printf("list.mem_size(); %d\n", list.mem_size()); // アイテムの全削除、アイテム用メモリも解放。 list.resize(4); // アイテムの数を4個にする return 0; } |
上記ソースは全て自由に改編して使ってかまいませんが必ず自己責任でね。