こんにちは、みんな!動的メモリ管理を学んだ後は、シーケンス テーブルを作成してデータを管理できるようになります。!!
シーケンス テーブルを理解する:
線形テーブルは、最も基本的かつ単純で、最も一般的に使用されるデータ構造です。線形リストはデータ構造の一種であり、同じ特性を持つ n データ要素の有限シーケンスです。
シーケンシャル テーブルは、コンピュータ メモリに配列の形式で保存される線形テーブルです。線形テーブルのシーケンシャル ストレージとは、連続したアドレスを持つ一連のストレージ ユニットを使用して、線形テーブルの各要素を順番に格納することを指します。データ要素は論理的に隣接しています。データ要素は、隣接する物理的な記憶装置に格納されます。つまり、データ要素間の論理的な隣接関係は、データ要素の物理的な格納の隣接関係を通じて反映されます。シーケンシャルな格納構造を使用する線形テーブルは、通常、線形テーブルと呼ばれます。シーケンシャルテーブル。シーケンス テーブルは、テーブル内のノードを、コンピュータ メモリ内の連続したアドレスを持つ一連の記憶ユニットに順番に格納します。
静的シーケンステーブルは配列のように固定サイズですが、動的シーケンステーブルは容量が足りない場合に拡張して大量のデータを格納できる効果が得られます!!!
1. まず、配列リストを表す構造体を作成します。
typedef int DATE;//重命名顺序表的数据类型
typedef struct ArrayList {
DATE* date;
size_t size;//顺序表长度
size_t capacity;//顺序表容量
}AL;
2. シーケンステーブルの全インターフェースの表示
void Init(AL* al);
void checkCapacity(AL* al);
void pushBack(AL* al, DATE info);
void pushFront(AL* al, DATE info);
void insertDate(AL* al,size_t pos, DATE info);
void printDate(AL* al);
void Erase(AL* al, size_t pos);
void PopBack(AL* al);
void PopFront(AL* al);
size_t FindDate(AL* al, DATE info);
void ExchangeDate(AL* al, size_t pos, DATE info);
void Deatory(AL* al);
3. 各インターフェース機能の紹介と実装原理
1. 初期化関数の実装
void Init(AL* al)
{
assert(al);
al->size = 0;
al->capacity = 4;//初始化容量为4
DATE* tmp = (DATE*)malloc(sizeof(DATE) * al->capacity);
if (tmp == NULL)
{
perror("malloc fail");
exit(-1);
}
al->date = tmp;
}
初期化シーケンステーブルの長さは 0、容量は 4!
2. キャパシティー機能の実装を確認する
void checkCapacity(AL* al)
{
if (al->size == al->capacity)
{
DATE* tmp = (DATE*)realloc(al->date, sizeof(DATE) * al->capacity*2);
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
al->capacity *= 2;
al->date = tmp;
printf("扩容成功!\n");
}
}
長さが容量と同じ場合は、容量を拡張する必要があることを意味しますので、容量を2倍に拡張します。
3. 末尾挿入機能の実装
void pushBack(AL* al, DATE info)
{
assert(al);
checkCapacity(al);
al->date[al->size] = info;
al->size++;
}
末尾挿入とは、
サイズの最後に挿入する値を書き込み、長さに 1 を加算することを意味します。
4. ヘッドプラグ機能の実装
void pushFront(AL* al, DATE info)
{
assert(al);
checkCapacity(al);
if (al->size == 0)
{
al->date[0] = info;
al->size++;
}
else
{
size_t end = al->size;
while (end)
{
al->date[end] = al->date[end-1];
end--;
}
al->date[0] = info;
al->size++;
}
}
データを挿入する場合、以下のデータを後ろに移動する必要があり、移動中に容量を超える可能性があるため、挿入時に拡張判断が必要となります。
移動方法は上記の通りです
5.末尾削除機能
void PopBack(AL* al)
{
assert(ps);
assert(al->size > 0);
al->size--;
}
最後のデータを削除するには、長さを 1 つ減らします。
6. 先頭削除機能
void PopFront(AL* al)
{
assert(al->size > 0);
int begin = 1;
while (begin<al->size)
{
al->date[begin - 1] = al->date[begin];
begin++;
}
al->size--;
}
移動シーケンスの方法は次のとおりです:
変数 begin=1 を定義し、最初にデータ 2 をデータ 1 の位置に移動し、対応する演算は
al->date[begin - 1] = al->date[begin]; です。 begin++, データ 3 をデータ 2 の位置に、データ 4 をデータ 3 の位置に順に移動します。ループの最終回は、データ 5 をデータ 4 の位置に移動する、つまり begin=4、al->size=5 のとき、ループの判定条件は beginsize で、ループ終了後は al->size となります。 –
;
7. 任意の位置のデータを削除する機能の実装
void Erase(AL* al, size_t pos)
{
assert(al);
assert(pos >= 0 && pos <= al->size);
if (al->size == 0)
{
printf("暂无数据!!\n");
return;
}
size_t end = pos;
while (end<al->size-1)
{
![在这里插入图片描述](https://img-blog.csdnimg.cn/a1a63c6776c142eeb77e15536b8f9a53.png#pic_center)
al->date[end] = al->date[end + 1];
end++;
}
al->size--;
}
データを削除するには、この位置以降のすべての要素を 1 位置だけ前に移動する必要があります
。添字は size_t で表されるため、先頭を削除するときにサイズを比較するには、符号なし -1 と 0 のループ条件を把握する必要があります。
番号 3 を削除し、データ 3 の後のデータを前に移動したい場合、最初のステップは、データ 4 をデータ 3 の位置に移動し、変数 end=pos=2 を定義することです。対応する操作は al-> です。 date[end ] = al->date[end+1]; の後に end++; により、データ 5 がデータ 4 の先頭に移動されます。最後のループはデータ 5 をデータ 4 に移動するもので、最終的に end が 3 になり、al->size=5 となり、ループの判定条件は end< al->size-1 となり、ループの終了となります。 al->size– になります。
8. 任意の位置にデータを挿入する機能の実装
void insertDate(AL* al, size_t pos, DATE info)
{
assert(al);
assert(pos >= 0 && pos <= al->size);
checkCapacity(al);
int end = al->size;
while (end > pos)
{
al->date[end] = al->date[end - 1];
end--;
}
al->date[pos] = info;
al->size++;
}
添字 Yi クラスは size_t で表現されるため、ヘッダ挿入時に符号なし -1 と 0 のループ条件を比較する場合の状況を把握する必要があります。
任意の位置に挿入するには、挿入位置と後続のデータを一度に 1 位置ずつ後方に移動する必要があります。
9. 先頭プラグ削除、先頭削除、末尾削除機能の改善
任意の挿入と任意の削除を記述した後、先頭プラグの削除と先頭の削除と末尾の削除関数を改良し、関数本体で任意の挿入と任意の削除関数を直接呼び出すことができます。
void pushFront(AL* al, DATE info)
{
assert(al);
checkCapacity(al);
if (al->size == 0)
{
al->date[0] = info;
al->size++;
}
else
{
insertDate(al, 0, info);
}
}
void pushBack(AL* al, DATE info)
{
assert(al);
checkCapacity(al);
insertDate(al, al->size, info);
}
void PopBack(AL* al)
{
assert(al);
if (al->size == 0)
{
printf("暂无数据!!\n");
return;
}
Erase(al, al->size);
}
void PopFront(AL* al)
{
assert(al);
if (al->size == 0)
{
printf("暂无数据!!\n");
return;
}
Erase(al, 0);
}
先頭挿入はinsert関数を呼び出して0の位置に挿入、
末尾挿入はinsert関数を呼び出してsizeの位置に挿入、
先頭削除はErase関数を呼び出して0の位置を削除、
末尾削除はサイズ位置を削除する消去機能。
10. データ検索機能の実装
size_t FindDate(AL* al, DATE info)
{
assert(al);
for (size_t i = 0; i < al->size; i++)
{
if (al->date[i] == info)
return i;
}
return -1;
}
コンビニエンス シーケンス テーブル。検索する必要があるデータが見つかった場合はその添え字を返し、そうでない場合は -1 を返します。
11. データの変更
void ExchangeDate(AL* al, size_t pos, DATE info)
{
assert(al);
assert(pos >= 0 && pos <= al->size);
al->date[pos] = info;
}
変更対象のデータが存在するか確認してから変更するため、
通常は検索機能と併用します。
12. 破壊順序表
シーケンス テーブルはヒープ領域のメモリを解放するため、シーケンス テーブルを使用した後は、割り当てられたメモリを解放する必要があります。
void Deatory(AL* al)
{
assert(al);
free(al->date);
al->date=NULL;
al->capacity = al->size = 0;
}
シーケンステーブルを破棄し、シーケンステーブルの容量を0にし、シーケンステーブルの有効データ数を0にして、日付ポインタが指す動的に割り当てられたメモリ空間を解放します。 all p 指す空間が初期化されず、日付がワイルドポインタとなる ワイルドポインタを防ぐため、日付をヌルポインタに設定します。
データ構造部分の共有 - シーケンス テーブルはここで終了です。閲覧していただいた皆様、ありがとうございました。!!