個人ホームページShuiyuemengjinghua
個人コラムC言語、データ構造
記事ディレクトリ
- 1. シーケンステーブル
- 2. 実装アイデア
-
- 1. 保管構造
- 2. シーケンステーブルの初期化(SeqListInit)
- 3. シーケンステーブルの破棄(SeqListDestroty)
- 4. 印刷シーケンステーブル(SeqListPrint)
- 5. シーケンステーブル末尾挿入(SeqListPushBack)と容量チェック(SeqListCheckCapacity)
- 6. シーケンスヘッダ挿入(SeqLsitPushFront)
- 7. 配列表末尾削除(SeqListPopBack)
- 8. シーケンスヘッダー削除(SeqListPopFront)
- 9. シーケンステーブルルックアップ(SeqListFind)
- 10. pos 位置の前に要素を挿入 (SeqListInsert)
- 11. pos 位置の値を削除(SeqListErase)
- 3. コードの実装
- 要約する
1. シーケンステーブル
順序テーブルは、連続した物理構造を持つ記憶装置にデータ要素を順番に格納する線形構造であり、通常は配列に格納されます。
シーケンス テーブルは通常、次の 2 つのタイプに分類されます。
- 静的シーケンス テーブル: 固定長配列を使用して実装
- 動的数値テーブル: 動的に開かれた配列を使用して実装されます。
この記事では、動的に開発された配列 (動的シーケンス テーブル) を使用してシーケンス テーブルを実装します。実装する機能は以下の通りです。
//初始化顺序表
void SeqListInit(SeqList* ps);
//销毁顺序表
void SeqListDestroty(SeqList* ps);
//打印顺序表
void SeqListPrint(SeqList* ps);
//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDateType x);
//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDateType x);
//顺序表尾删
void SeqListPopBack(SeqList* ps);
//顺序表头删
void SeqListPopFront(SeqList* ps);
//顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);
//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDateType x);
//删除pos位置的值
void SeqListErase(SeqList* ps, int pos);
//检查容量
void SeqListCheckCapacity(SeqList* ps);
2. 実装アイデア
絵を描くとわかりやすい!!!
1. 保管構造
将来、シーケンス テーブル内の記憶要素の型を変更できるように、int 型の名前を SLDataType に変更します。
ポインタ データは動的に開かれたスペースを指し、変数 sz は有効なデータ要素を記録し、可変容量は動的に開かれたスペースのサイズを記録します。
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* data;
int sz;
int capacity;
}SeqList;
2. シーケンステーブルの初期化(SeqListInit)
スペースを動的に開き、データ ポインターを使用してスペースの最初のアドレスを保存します。
このとき、dataが指す空間の有効要素は0であるため、sz == 0となり、可変容量はこのとき開いた空間のサイズに等しい。
#define SIZE 4
void SeqListInit(SeqList* ps)
{
ps->data = (SLDataType*)malloc(sizeof(SLDataType) * SIZE);
if (ps->data == NULL)
{
perror("malloc");
exit(-1);
}
ps->sz = 0;
ps->capacity = SIZE;
}
3. シーケンステーブルの破棄(SeqListDestroty)
freeで空けた空間はdata == NULLとなり、このときデータの有効要素は0、空間サイズは0となり、sz = 0、capacity = 0となります。
//销毁顺序表
void SeqListDestroty(SeqList* ps)
{
assert(ps);
//free(ps);
free(ps->data);
ps->data = NULL;
ps->sz = 0;
ps->capacity = 0;
}
4. 印刷シーケンステーブル(SeqListPrint)
この関数は非常に単純で、開いた空間を 1 回横断するだけであり、範囲 (0, sz) に注意してください。
//打印顺序表
void SeqListPrint(SeqList* ps)
{
assert(ps);
for (int i = 0; i < ps->sz; i++)
{
printf("%d ", ps->data[i]);
}
printf("\n");
}
5. シーケンステーブル末尾挿入(SeqListPushBack)と容量チェック(SeqListCheckCapacity)
データを追加するたびに、データを追加する前にスペースのサイズが十分であるかどうかを確認する必要があります
-
容量の確認
データを挿入する前に、スペースサイズが十分であるかどうかを確認します (sz == Capacity)。スペースサイズが十分でない場合は、スペースサイズを拡張し、capacity には新しいスペースサイズが記録されます。 -
最後に要素を挿入する
変数 sz は、空間内の有効な要素の数を表すだけでなく、新しいデータ要素が配置される位置も表します。したがって、要素を末尾に挿入するのに十分なスペースがある限り、data[sz] にデータを配置するだけでよく、sz に 1 を追加することを忘れないでください。
//检查容量
void SeqListCheckCapacity(SeqList* ps)
{
SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * ps->capacity * 2);
if (tmp == NULL)
{
perror("realloc");
exit(-1);
}
ps->data = tmp;
ps->capacity *= 2;
}
//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
assert(ps);
if (ps->sz == ps->capacity)
{
SeqListCheckCapacity(ps);
}
ps->data[ps->sz] = x;
ps->sz++;
}
6. シーケンスヘッダ挿入(SeqLsitPushFront)
順序表の末尾挿入、末尾削除以外はデータへの移動は不要ですが、その他の追加、削除はデータへの移動が必要です。
先頭にデータを挿入するには、スペースのサイズを確認してからデータを遡ってdata[0]にデータを入れ、szに1を加えます。
//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDataType x)
{
assert(ps);
if (ps->sz == ps->capacity)
{
SeqListCheckCapacity(ps);
}
int end = ps->sz;
while (end > 0)
{
ps->data[end] = ps->data[end - 1];
end--;
}
ps->data[0] = x;
ps->sz++;
}
7. 配列表末尾削除(SeqListPopBack)
変数 sz は有効なデータの数を表すため、sz から 1 を引いた場合、最後のデータが削除されることを意味します。
//顺序表尾删
void SeqListPopBack(SeqList* ps)
{
assert(ps);
assert(ps->sz != 0);
ps->sz--;
}
8. シーケンスヘッダー削除(SeqListPopFront)
先頭のデータを削除するには、データを後ろから前に移動し、最初のデータを上書きし、sz から 1 を減算します。
//顺序表头删
void SeqListPopFront(SeqList* ps)
{
assert(ps);
assert(ps->sz != 0);
for (int i = 0; i < ps->sz - 1; i++)
{
ps->data[i] = ps->data[i + 1];
}
ps->sz--;
}
9. シーケンステーブルルックアップ(SeqListFind)
動的に開かれた配列を走査し、見つかった場合は添え字を戻し、見つからない場合は -1 を戻します。
//顺序表查找
int SeqListFind(SeqList* ps, SLDataType x)
{
assert(ps);
for (int i = 0; i < ps->sz; i++)
{
if (ps->data[i] == x)
{
return i;
}
}
return -1;
}
10. pos 位置の前に要素を挿入 (SeqListInsert)
まず、スペースの容量が十分であるかどうか、および挿入する位置が正当であるかどうか (順序テーブル内の有効なデータ内にある必要があります) を確認してから、pos で添え字が付いたデータを後方に移動し、データを data[pos] に配置し、追加します。サイズ 1。
この機能の考え方はシンプルですが、以下の2点に注意してください。
- pos == 0 の場合、配列表の最初の要素の前に要素を挿入するか、配列表の先頭を挿入することを意味します。
- pos == sz の場合、sz は次のデータが配置される位置も示すことがわかっているため、次のデータが配置される位置の前に要素を挿入します。これはシーケンス テーブルの最後の挿入ではありません。 。
この点を理解した上で、この機能を利用して、将来的にヘッドプラグとテールプラグを再利用することができます。注文リストを手で破れるのは便利です
//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->sz);
if (ps->sz == ps->capacity)
{
SeqListCheckCapacity(ps);
}
int end = ps->sz;
while (end > pos)
{
ps->data[end] = ps->data[end - 1];
end--;
}
ps->data[pos] = x;
ps->sz++;
}
11. pos 位置の値を削除(SeqListErase)
位置 pos のデータを削除するには、まず pos の有効性をチェックし ([0, sz-1] に属している必要があります)、データを後ろから前 (sz マイナス 1) に移動します。
この機能の考え方はシンプルですが、以下の2点に注意してください。
- pos == 0 の場合、最初のデータを削除する、つまり先頭を削除することを意味します。
- pos == sz - 1 の場合は、最後のデータを削除する、つまり末尾を削除することを意味します。
したがって、末尾の削除関数と先頭の削除関数については、この関数を再利用することもできます。
//删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->sz);
for (int i = pos; i < ps->sz - 1; i++)
{
ps->data[i] = ps->data[i + 1];
}
ps->sz--;
}
3. コードの実装
先頭の削除、先頭の挿入、末尾の削除、末尾の挿入には SeqListInsert と SeqListErase を再利用しました。
SeqList.h ファイルには関数宣言と構造体宣言が格納されます。
SeqList.c ファイルには関数定義が格納されます。
//SeqList.h 文件
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define SIZE 4
typedef int SLDataType;
typedef struct SeqList
{
SLDataType* data;
int sz;
int capacity;
}SeqList;
//初始化顺序表
void SeqListInit(SeqList* ps);
//销毁顺序表
void SeqListDestroty(SeqList* ps);
//打印顺序表
void SeqListPrint(SeqList* ps);
//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDateType x);
//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDateType x);
//顺序表尾删
void SeqListPopBack(SeqList* ps);
//顺序表头删
void SeqListPopFront(SeqList* ps);
//顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);
//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDateType x);
//删除pos位置的值
void SeqListErase(SeqList* ps, int pos);
//检查容量
void SeqListCheckCapacity(SeqList* ps);
//SeqList.c 文件
#include "SeqList.h"
//初始化顺序表
void SeqListInit(SeqList* ps)
{
ps->data = (SLDataType*)malloc(sizeof(SLDataType) * SIZE);
if (ps->data == NULL)
{
perror("malloc");
exit(-1);
}
ps->sz = 0;
ps->capacity = SIZE;
}
//检查容量
void SeqListCheckCapacity(SeqList* ps)
{
SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * ps->capacity * 2);
if (tmp == NULL)
{
perror("realloc");
exit(-1);
}
ps->data = tmp;
ps->capacity *= 2;
}
//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
/*assert(ps);
if (ps->sz == ps->capacity)
{
SeqListCheckCapacity(ps);
}
ps->data[ps->sz] = x;
ps->sz++;*/
SeqListInsert(ps, ps->sz, x);
}
//打印顺序表
void SeqListPrint(SeqList* ps)
{
assert(ps);
for (int i = 0; i < ps->sz; i++)
{
printf("%d ", ps->data[i]);
}
printf("\n");
}
//销毁顺序表
void SeqListDestroty(SeqList* ps)
{
assert(ps);
//free(ps);
free(ps->data);
ps->data = NULL;
ps->sz = 0;
ps->capacity = 0;
}
//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDataType x)
{
/*assert(ps);
if (ps->sz == ps->capacity)
{
SeqListCheckCapacity(ps);
}
int end = ps->sz;
while (end > 0)
{
ps->data[end] = ps->data[end - 1];
end--;
}
ps->data[0] = x;
ps->sz++;*/
SeqListInsert(ps, 0, x);
}
//顺序表尾删
void SeqListPopBack(SeqList* ps)
{
/*assert(ps);
assert(ps->sz != 0);
ps->sz--;*/
SeqListErase(ps, ps->sz - 1);
}
//顺序表头删
void SeqListPopFront(SeqList* ps)
{
/*assert(ps);
assert(ps->sz != 0);
for (int i = 0; i < ps->sz - 1; i++)
{
ps->data[i] = ps->data[i + 1];
}
ps->sz--;*/
SeqListErase(ps, 0);
}
//顺序表查找
int SeqListFind(SeqList* ps, SLDataType x)
{
assert(ps);
for (int i = 0; i < ps->sz; i++)
{
if (ps->data[i] == x)
{
return i;
}
}
return -1;
}
//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos <= ps->sz);
if (ps->sz == ps->capacity)
{
SeqListCheckCapacity(ps);
}
int end = ps->sz;
while (end > pos)
{
ps->data[end] = ps->data[end - 1];
end--;
}
ps->data[pos] = x;
ps->sz++;
}
//删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos < ps->sz);
for (int i = pos; i < ps->sz - 1; i++)
{
ps->data[i] = ps->data[i + 1];
}
ps->sz--;
}
要約する
以上がシーケンステーブルの実装です。ご協力ありがとうございます!!!