C++における単一チェーンテーブルの作成と操作
データの準備
チェーンテーブル操作で使用する変数およびデータ構造の準備
サンプルコードは次のとおりです.
チェーンテーブルデータ要素のタイプDataおよびチェーンテーブルのデータ構造CLTypeを定義します.ノードの特定のデータは構造データに保存され、ポインタnextNodeは次のノードを指すために使用されます.
このチェーンテーブルはクラスの学生の記録であり,keyは学号を表し,nameは学生の名前,ageは年齢であると考えられる.
ノードの追加
追加ノードはチェーンテーブルの末尾にノードを追加します.表末尾ノードのアドレス部分は元々空のアドレスNULLが保存されていたが、この場合は新規ノードのアドレス(すなわち、元の表末尾ノードが新規ノードを指す)に設定し、新規ノードのアドレス部分を空のアドレスNULL、すなわち新規ノードが表末尾に設定する必要がある.
一般に、チェーンテーブルにはヘッダポインタheadが1つしかないため、最後にノードを追加するには、最後のノード(すなわちテーブルの最後)が見つかるまで、ヘッダheadから個々のチェックを開始する必要があります.
ノードを追加する手順は次のとおりです.
(1)まずメモリアドレスを割り当て,新規ノードを保存する.
(2)最後のノード(すなわち表末尾)が見つかるまで、先頭ポインタheadから1つずつチェックを開始する.
(3)表末尾ノードのアドレスを新規ノードのアドレスに設定する.
(4)新規ノードのアドレス部分を空アドレスNULLとし,すなわち新規ノードが表末尾となる.
サンプルコードは次のとおりです.
入力パラメータheadはチェーンヘッダポインタ、入力パラメータnodeDataはノードに保存されたデータです.プログラムではnewキーを使用してダイナミックスペースを申請し、内部割り当てに成功するとnodeにメモリ領域へのポインタが保存されます.
次に、入力されたnodeDataを申請のメモリ領域に保存し、次のノードへのポインタ値をNULLに設定します.
ヘッドノードの挿入
ヘッダノードの挿入とは、チェーンテーブルのヘッダにノードを追加するプロセスであり、テーブルの最後にノードを挿入するのとは逆に、ヘッダにノードを挿入し、ヘッダノードとして使用します.
ヘッダノードを挿入するには、次の手順に従います.
(1)まずメモリを割り当て,新しいノードを保存する.
(2)新たな姉弟の頭の針headを指す接点を
(3)次にヘッダポインタheadを新規ノードに向ける
サンプルコードは次のとおりです.
入力パラメータheadはチェーンヘッダポインタ、入力パラメータnodeDataはノードに保存されているデータです.プログラムではまずnewキーを使用して新しいセーブポイントのメモリ領域を申請し、申請に成功するとnodeはメモリ領域へのポインタを保存します.
次に、入力されたnodeDataを申請のメモリ領域に保存し、新しいノードがヘッダポインタheadが指すノードを指し、ヘッダポインタheadが新しいノードを再び指すように設定します.
ノードの検索
ノードの検索とは、チェーンテーブル構造で必要な要素を検索することです.チェーンテーブル構造では、一般に、ノード番号で検索するクラスとキーワードで検索するクラスに分けられます.
ノード番号によるクエリー
つまり、チェーンテーブルのノードの数をクエリーします.その例のコードは次のとおりです.
入力パラメータheadはチェーンヘッダポインタであり、入力パラメータkはクエリーするノードのシーケンス番号である.シーケンス番号で複数回ループし、そのノードを指すポインタを取得し、ポインタを返します.
キーワードによるクエリー
すなわち、チェーンテーブルのノードのキーワードに基づいてクエリーを行い、学生の名前(name)をクエリーする例では、次のコードの例を示します.
入力パラメータheadはチェーンヘッダポインタ、入力パラメータnameはクエリーする同級生の名前です.すべての学生の名前を検索し、検索した名前と同じノードの名前がある場合は、そのノードのポインタを返します.
ノードの挿入
ノードを挿入すると、チェーンテーブルの中間部分の位置にノードが追加されます.
ノードを挿入するには、次の手順に従います.
(1)メモリ領域を割り当て,新規ノードを保存する.
(2)挿入する論理位置,すなわちそのノードの後ろに挿入する論理位置を見つける.
(3)挿入位置ノードのポインタを修正し、新規ノードを指し、新規ノードが元の挿入位置が指すノードを指すようにする.
サンプルコードは次のとおりです.
入力パラメータheadはチェーンテーブルヘッダポインタ、入力パラメータfindkeyはチェーンテーブルで検索するノードキーであり、このノードを見つけた後、そのノードの後ろにノードデータを追加し、nodeDataは新しいノードのデータである.プログラムではまずnewを使用してノード空間を申請し、CLFindNodeNum関数を呼び出してノードを検索し、挿入操作を実行します.
ノードの削除
削除ノードとは、チェーンテーブル内のノードデータを削除することであり、その位置前後のノードには影響しません.
ノードを削除するには、次の手順に従います.
(1)削除するノードを検索する.
(2)前のノードを現在のノードの次のノードに向ける.
(3)このノードを削除する
削除ノードは、削除するノードをノードのシーケンス番号で決定したり、削除するノードをノードのキーワードで決定したりすることができます.
キーワードによるノードの削除を例にとると、次のようなコードがあります.
headはチェーンヘッダポインタであり,パラメータnameを入力して削除する同級生の名前を表す.プログラムでは、削除するノードをキーワードでチェーンテーブル全体で検索します.削除されたノードが見つかった場合、前のノード(nodeポインタが指すノード)が現在のノード(hポインタが指すノード)の次のノードを指すように設定されます.すなわち、論理的にノードを削除し、そのノードに対してdelete操作を実行し、ノードが使用するメモリ領域を解放します.つまり、物理的に削除します.
チェーンテーブルの長さの計算
チェーンテーブルの長さを計算します.つまり、チェーンテーブル内のノードの数を統計します.シーケンステーブルではチェーンテーブルの長さを計算するのが便利ですが、チェーンテーブルは物理的に連続的に格納されていないため、チェーンテーブルの長さはチェーンテーブルを巡回することによって得る必要があります.
サンプルコードは次のとおりです.
パラメータheadはチェーンテーブルのヘッダポインタであり,プログラムではwhileによりポインタを遍歴し,Lenはカウンタとしてループの回数を記録することでチェーンテーブルの長さを求め,ポインタがNULLのときにカットオフし,カウンタの値を返す.
すべてのノードを表示
すべてのノードを巡り、出力します.
出力ノードの関数は、戻り値がなく、voidとして定義されています.毎回CLTypeタイプのノードからnodeDataの値を取得する
チェーンテーブル操作の完全な例
完全な例のコードは長いので、辛抱強く見てください......:)
プログラム実行結果の例:
チェーンテーブル操作で使用する変数およびデータ構造の準備
サンプルコードは次のとおりです.
struct Data //
{
string key; //
string name;
int age;
};
struct CLType //
{
Data nodeData;
CLType *nextNode;
};
チェーンテーブルデータ要素のタイプDataおよびチェーンテーブルのデータ構造CLTypeを定義します.ノードの特定のデータは構造データに保存され、ポインタnextNodeは次のノードを指すために使用されます.
このチェーンテーブルはクラスの学生の記録であり,keyは学号を表し,nameは学生の名前,ageは年齢であると考えられる.
ノードの追加
追加ノードはチェーンテーブルの末尾にノードを追加します.表末尾ノードのアドレス部分は元々空のアドレスNULLが保存されていたが、この場合は新規ノードのアドレス(すなわち、元の表末尾ノードが新規ノードを指す)に設定し、新規ノードのアドレス部分を空のアドレスNULL、すなわち新規ノードが表末尾に設定する必要がある.
一般に、チェーンテーブルにはヘッダポインタheadが1つしかないため、最後にノードを追加するには、最後のノード(すなわちテーブルの最後)が見つかるまで、ヘッダheadから個々のチェックを開始する必要があります.
ノードを追加する手順は次のとおりです.
(1)まずメモリアドレスを割り当て,新規ノードを保存する.
(2)最後のノード(すなわち表末尾)が見つかるまで、先頭ポインタheadから1つずつチェックを開始する.
(3)表末尾ノードのアドレスを新規ノードのアドレスに設定する.
(4)新規ノードのアドレス部分を空アドレスNULLとし,すなわち新規ノードが表末尾となる.
サンプルコードは次のとおりです.
CLType * CLAddEnd(CLType *head,Data nodeData)
{
CLType *node,*htemp;
if(!(node = new CLType))
{
cout<<" !"<<endl; //
return NULL;
}
else
{
node->nodeData = nodeData; //
node->nextNode = NULL; // ,
if(head == NULL) //
{
head = node;
return head;
}
htemp = head;
while(htemp->nextNode != NULL) //
{
htemp = htemp->nextNode;
}
htemp->nextNode = node;
return head;
}
}
入力パラメータheadはチェーンヘッダポインタ、入力パラメータnodeDataはノードに保存されたデータです.プログラムではnewキーを使用してダイナミックスペースを申請し、内部割り当てに成功するとnodeにメモリ領域へのポインタが保存されます.
次に、入力されたnodeDataを申請のメモリ領域に保存し、次のノードへのポインタ値をNULLに設定します.
ヘッドノードの挿入
ヘッダノードの挿入とは、チェーンテーブルのヘッダにノードを追加するプロセスであり、テーブルの最後にノードを挿入するのとは逆に、ヘッダにノードを挿入し、ヘッダノードとして使用します.
ヘッダノードを挿入するには、次の手順に従います.
(1)まずメモリを割り当て,新しいノードを保存する.
(2)新たな姉弟の頭の針headを指す接点を
(3)次にヘッダポインタheadを新規ノードに向ける
サンプルコードは次のとおりです.
CLType *CLAddFirst(CLType *head,Data nodeData)
{
CLType *node;
if(!(node = new CLType))
{
cout<<" "<<endl;
return NULL;
}
else
{
node->nodeData = nodeData; //
node->nextNode = head; //
head = node; //
return head;
}
}
入力パラメータheadはチェーンヘッダポインタ、入力パラメータnodeDataはノードに保存されているデータです.プログラムではまずnewキーを使用して新しいセーブポイントのメモリ領域を申請し、申請に成功するとnodeはメモリ領域へのポインタを保存します.
次に、入力されたnodeDataを申請のメモリ領域に保存し、新しいノードがヘッダポインタheadが指すノードを指し、ヘッダポインタheadが新しいノードを再び指すように設定します.
ノードの検索
ノードの検索とは、チェーンテーブル構造で必要な要素を検索することです.チェーンテーブル構造では、一般に、ノード番号で検索するクラスとキーワードで検索するクラスに分けられます.
ノード番号によるクエリー
つまり、チェーンテーブルのノードの数をクエリーします.その例のコードは次のとおりです.
CLType *CLFindNodeNum(CLType *head,int k)
{
CLType *htemp;
int i = 1;
htemp = head; //
for(i = 1;i<k&&htemp;i++) //
{
htemp = htemp->nextNode;
}
return htemp; // k
}
入力パラメータheadはチェーンヘッダポインタであり、入力パラメータkはクエリーするノードのシーケンス番号である.シーケンス番号で複数回ループし、そのノードを指すポインタを取得し、ポインタを返します.
キーワードによるクエリー
すなわち、チェーンテーブルのノードのキーワードに基づいてクエリーを行い、学生の名前(name)をクエリーする例では、次のコードの例を示します.
CLType *CLFindNodeKey(CLType *head,string name)
{
CLType * htemp;
htemp = head; //
while(htemp)
{
if(htemp->nodeData.name == name) //
{
return htemp; //
}
htemp = htemp->nextNode;
}
return NULL;
}
入力パラメータheadはチェーンヘッダポインタ、入力パラメータnameはクエリーする同級生の名前です.すべての学生の名前を検索し、検索した名前と同じノードの名前がある場合は、そのノードのポインタを返します.
ノードの挿入
ノードを挿入すると、チェーンテーブルの中間部分の位置にノードが追加されます.
ノードを挿入するには、次の手順に従います.
(1)メモリ領域を割り当て,新規ノードを保存する.
(2)挿入する論理位置,すなわちそのノードの後ろに挿入する論理位置を見つける.
(3)挿入位置ノードのポインタを修正し、新規ノードを指し、新規ノードが元の挿入位置が指すノードを指すようにする.
サンプルコードは次のとおりです.
CLType *CLInsertNode(CLType *head,int k,Data nodeData)
{
CLType *node,*nodetemp;
if(!(node = new CLType)) //
{
cout<<" "<<endl;
return NULL;
}
else
{
node->nodeData = nodeData; //
nodetemp=CLFindNodeNum(head,k-1);// ( )
if(nodetemp)
{
node->nextNode = nodetemp->nextNode;//
nodetemp->nextNode = node; //
}
else
{
cout<<" "<<endl;
delete node;
}
}
return head; //
}
入力パラメータheadはチェーンテーブルヘッダポインタ、入力パラメータfindkeyはチェーンテーブルで検索するノードキーであり、このノードを見つけた後、そのノードの後ろにノードデータを追加し、nodeDataは新しいノードのデータである.プログラムではまずnewを使用してノード空間を申請し、CLFindNodeNum関数を呼び出してノードを検索し、挿入操作を実行します.
ノードの削除
削除ノードとは、チェーンテーブル内のノードデータを削除することであり、その位置前後のノードには影響しません.
ノードを削除するには、次の手順に従います.
(1)削除するノードを検索する.
(2)前のノードを現在のノードの次のノードに向ける.
(3)このノードを削除する
削除ノードは、削除するノードをノードのシーケンス番号で決定したり、削除するノードをノードのキーワードで決定したりすることができます.
キーワードによるノードの削除を例にとると、次のようなコードがあります.
int CLDeleteNode(CLType *head,string name)
{
CLType *node,*htemp; //node
htemp = head;
node = head;
while(htemp)
{
if(htemp->nodeData.name == name)// ,
{
node->nextNode = htemp->nextNode;//
delete htemp; // ( , )
return 1;
}
else
{
node = htemp; //
htemp = htemp->nextNode; //
}
}
return 0; //
}
headはチェーンヘッダポインタであり,パラメータnameを入力して削除する同級生の名前を表す.プログラムでは、削除するノードをキーワードでチェーンテーブル全体で検索します.削除されたノードが見つかった場合、前のノード(nodeポインタが指すノード)が現在のノード(hポインタが指すノード)の次のノードを指すように設定されます.すなわち、論理的にノードを削除し、そのノードに対してdelete操作を実行し、ノードが使用するメモリ領域を解放します.つまり、物理的に削除します.
チェーンテーブルの長さの計算
チェーンテーブルの長さを計算します.つまり、チェーンテーブル内のノードの数を統計します.シーケンステーブルではチェーンテーブルの長さを計算するのが便利ですが、チェーンテーブルは物理的に連続的に格納されていないため、チェーンテーブルの長さはチェーンテーブルを巡回することによって得る必要があります.
サンプルコードは次のとおりです.
int CLLength(CLType *head)
{
CLType *htemp;
int Len = 0;
htemp = head;
while(htemp) //
{
Len++; //
htemp = htemp->nextNode; //
}
return Len;
}
パラメータheadはチェーンテーブルのヘッダポインタであり,プログラムではwhileによりポインタを遍歴し,Lenはカウンタとしてループの回数を記録することでチェーンテーブルの長さを求め,ポインタがNULLのときにカットオフし,カウンタの値を返す.
すべてのノードを表示
すべてのノードを巡り、出力します.
void CLAllNode(CLType *head)
{
CLType *htemp;
htemp = head;
while(htemp) //
{
nodeData = htemp->nodeData; //
cout<<"key:"<<nodeData.key<<",name:"<<nodeData.name<<",age:"<<nodeData.age<<endl;
htemp = htemp->nextNode; //
}
}
出力ノードの関数は、戻り値がなく、voidとして定義されています.毎回CLTypeタイプのノードからnodeDataの値を取得する
チェーンテーブル操作の完全な例
完全な例のコードは長いので、辛抱強く見てください......:)
#include<iostream>
#include<string>
using namespace std;
struct Data //
{
string key; //
string name;
int age;
};
struct CLType //
{
Data nodeData;
CLType *nextNode;
};
CLType * CLAddEnd(CLType *head,Data nodeData)
{
CLType *node,*htemp;
if(!(node = new CLType))
{
cout<<" !"<<endl; //
return NULL;
}
else
{
node->nodeData = nodeData; //
node->nextNode = NULL; // ,
if(head == NULL) //
{
head = node;
return head;
}
htemp = head;
while(htemp->nextNode != NULL) //
{
htemp = htemp->nextNode;
}
htemp->nextNode = node;
return head;
}
}
CLType *CLAddFirst(CLType *head,Data nodeData)
{
CLType *node;
if(!(node = new CLType))
{
cout<<" "<<endl;
return NULL;
}
else
{
node->nodeData = nodeData; //
node->nextNode = head; //
head = node; //
return head;
}
}
CLType *CLFindNodeNum(CLType *head,int k)
{
CLType *htemp;
int i = 1;
htemp = head; //
for(i = 1;i<k&&htemp;i++) //
{
htemp = htemp->nextNode;
}
return htemp; // k
}
CLType *CLFindNodeName(CLType *head,string name)
{
CLType * htemp;
htemp = head; //
while(htemp)
{
if(htemp->nodeData.name == name) //
{
return htemp; //
}
htemp = htemp->nextNode;
}
return NULL;
}
CLType *CLInsertNode(CLType *head,int k,Data nodeData)
{
CLType *node,*nodetemp;
if(!(node = new CLType)) //
{
cout<<" "<<endl;
return NULL;
}
else
{
node->nodeData = nodeData; //
nodetemp=CLFindNodeNum(head,k-1); // ( )
if(nodetemp)
{
node->nextNode = nodetemp->nextNode; //
nodetemp->nextNode = node; //
}
else
{
cout<<" "<<endl;
delete node;
}
}
return head; //
}
int CLDeleteNode(CLType *head,string name)
{
CLType *node,*htemp; //node
htemp = head;
node = head;
while(htemp)
{
if(htemp->nodeData.name == name) // ,
{
node->nextNode = htemp->nextNode; //
delete htemp; // ( , )
return 1;
}
else
{
node = htemp; //
htemp = htemp->nextNode; //
}
}
return 0; //
}
int CLLength(CLType *head)
{
CLType *htemp;
int Len = 0;
htemp = head;
while(htemp) //
{
Len++; //
htemp = htemp->nextNode; //
}
return Len;
}
void CLAllNode(CLType *head)
{
CLType *htemp;
Data nodeData;
htemp = head;
cout<<" :"<<CLLength(head)<<endl;
while(htemp) //
{
nodeData = htemp->nodeData; //
cout<<"key:"<<nodeData.key<<",name:"<<nodeData.name<<",age:"<<nodeData.age<<endl;
htemp = htemp->nextNode; //
}
}
int main()
{
CLType *node,*head = NULL;
Data nodeData;
string name;
int k;
cout<<" , : , , ( 0 )"<<endl;
while(1)
{
cin>>nodeData.key>>nodeData.name>>nodeData.age;
if(nodeData.age==0)break;
head=CLAddEnd(head,nodeData); //
}
CLAllNode(head); //
//
cout<<" , "<<endl;
cin>>nodeData.key>>nodeData.name>>nodeData.age;
head=CLAddFirst(head,nodeData);
CLAllNode(head);
//
cout<<" :"<<endl;
cin>>nodeData.key>>nodeData.name>>nodeData.age;
cout<<" :";
cin>>k;
head=CLInsertNode(head,k,nodeData);
CLAllNode(head);
//
cout<<" :";
cin>>k;
node=CLFindNodeNum(head,k);
cout<<" :"<<endl;
cout<<"key:"<<node->nodeData.key<<",name:"<<node->nodeData.name<<",age:"<<node->nodeData.age<<endl;
//
cout<<" :";
cin>>name;
node=CLFindNodeName(head,name);
cout<<" :"<<endl;
cout<<"key:"<<node->nodeData.key<<",name:"<<node->nodeData.name<<",age:"<<node->nodeData.age<<endl;
//
cout<<" , :";
cin>>name;
if(CLDeleteNode(head,name))cout<<" !"<<endl;
CLAllNode(head);
return 0;
}
プログラム実行結果の例: