コンテンツ
1.この章の焦点
1.リニアテーブルとシーケンシャルテーブルの概念
2.動的および静的シーケンステーブルインターフェイスの実装
3.オンライン0jトレーニング
2.線形テーブル
線形テーブルは、次の条件を満たすテーブルです。
- 線形リストは、同じ特性を持つn個のデータ要素の有限シーケンスです。
- 線形テーブルは、構造が論理的に線形ですが、物理構造が連続しているとは限りません。(ここでの物理構造は、通常、物理アドレス空間を指します)。
3.シーケンステーブル
次の条件を満たすシーケンステーブル:
- 線形テーブルです
- 物理的に連続
シーケンステーブルは、一般的に次のように分割できます。
- 静的シーケンステーブル:固定長の配列ストレージを使用します。
- 動的シーケンステーブル:動的に開発された配列ストレージを使用します。
第4に、静的シーケンステーブルインターフェイスの実装
4.1シーケンステーブルの初期化
void SeqListInint(SeqList* s)
{
assert(s);
memset(s->a, 0, sizeof(SeqListDataType) * MAXSIZE);
s->size = 0;
}
初期化する簡単な方法もあります。
シーケンステーブルsを作成するときに0を直接割り当てます。つまり、SeqList s = {0};
4.2シーケンステーブルの印刷
void SeqListPrint(SeqList* s)
{
int i = 0;
for (i = 0; i < s->size; i++)
{
printf("%d ", s->a[i]);
}
printf("\n");
}
シーケンステーブルのアドレスを渡し、forループステートメントを使用して、配列要素を段階的に出力します。
4.3テーブルフッターの順次挿入
void SeqListPushBack(SeqList* s, int x)
{
assert(s);
if (s->size == MAXSIZE)
{
printf("当前空间已满,无法继续添加\n");
exit(1);
}
s->a[s->size] = x;
s->size++;
}
最初にsが空かどうかを確認し、空の場合はエラーを報告し、次にいっぱいかどうかを確認します。いっぱいの場合は、いっぱいであることを確認してプログラムを終了します。
4.4テーブルフッターの順次削除
void SeqListPopBack(SeqList* s)
{
assert(s);
if (s->size == 0)
{
printf("当前顺序表为空,无法删除\n");
exit(1);
}
s->size--;
}
s-> size--だけで、最後の要素を0に設定する必要はありません。
4.5シーケンスヘッダープラグ
void SeqListPushFront(SeqList* s, int x)
{
if (s->size == MAXSIZE)
{
printf("空间已满,无法继续添加\n");
exit(1);
}
if (s->size == 0)
{
s->a[s->size] = x;
s->size++;
return;
}
else
{
int j = 0;
for (j = s->size - 1; j >= 0; j--)
{
s->a[j + 1] = s->a[j];
}
s->a[0] = x;
s->size++;
}
}
最初に要素を元に戻し、移動が完了した後に挿入する要素を挿入します。
4.6シーケンスヘッダーの削除
void SeqListPopFront(SeqList* s)
{
if (s->size == 0)
{
printf("当前顺序表为空,无法删除\n");
exit(1);
}
int j = 0;
for (j = 1; j <s->size; j++)
{
s->a[j - 1] = s->a[j];
}
s->size--;
}
要素を移動して前のコンテンツをカバーする方法を使用して、削除の目的を達成します。
4.7シーケンステーブルの任意の位置に挿入します
void SeqListInsert(SeqList* s, int pos, int x)
{
if (s->size == MAXSIZE)
{
printf("当前空间已满,无法继续添加\n");
exit(1);
}
if (pos < 0||pos>s->size)
{
printf("插入位置有误,无法插入\n");
exit(1);
}
if (pos == s->size)
{
s->a[s->size] = x;
s->size++;
return;
}
for (int j = s->size - 1; j >= pos; j--)
{
s->a[j + 1] = s->a[j];
}
s->a[pos] = x;
s->size++;
}
要素の位置を見つけ、要素を移動して、挿入する要素を配置します。
4.8シーケンステーブルの任意の場所を削除します
void SeqListErase(SeqList* s, int pos)
{
assert(s);
if (s->size == 0)
{
printf("顺序表为空,删除失败\n");
exit(1);
}
if (pos >= s->size || pos < 0)
{
printf("删除位置不存在\n");
exit(1);
}
int j = 0;
for (j = pos; j < s->size-1; j++)
{
s->a[j] = s->a[j + 1];
}
s->size--;
}
削除したい位置を見つけ、移動して削除したい要素を覆います。
5つの動的シーケンステーブルインターフェイスの実装
5.1シーケンステーブルの初期化
void SeqListInint(SeqList* s)
{
assert(s);
s->a = (DataType*)malloc(10 * sizeof(DataType));
s->size = 0;
s->capacity = 10;
}
要素数のサイズを0に設定します
スペースを開く
初期容量は10に設定されています
5.2シーケンステーブルの印刷
void SeqListPrint(SeqList* s)
{
assert(s);
int i = 0;
for (i = 0; i < s->size; i++)
{
printf("%d ", s->a[i]);
}
printf("\n");
}
5.3シーケンシャルテーブルフッター挿入
void SeqListPushBack(SeqList* s, DataType x)
{
assert(s);
SeqListCheckCapacity(s);
s->a[s->size] = x;
s->size++;
}
5.4テーブルフッターの順次削除
void SeqListPopBack(SeqList* s)
{
assert(s);
if (s->size == 0)
{
printf("当前顺序表为空,删除失败\n");
exit(1);
}
s->size--;
}
5.5シーケンスヘッダープラグ
void SeqListPushFront(SeqList* s, DataType x)
{
assert(s);
SeqListCheckCapacity(s);
if (s->size == 0)
{
s->a[0] = x;
s->size++;
}
else
{
int end = s->size - 1;
while (end >= 0)
{
s->a[end + 1] = s->a[end];
end--;
}
s->a[0] = x;
s->size++;
}
}
5.6シーケンスヘッダーの削除
void SeqListPopFront(SeqList* s)
{
assert(s);
if (s->size == 0)
{
printf("当前顺序表为空,无法删除\n");
exit(1);
}
if (s->size == 1)
{
s->size--;
return;
}
else
{
int i = 0;
for (i = 0; i <=s->size-2 ; i++)
{
s->a[i] = s->a[i + 1];
}
s->size--;
}
}
5.7シーケンステーブルの任意の位置に挿入します
void SeqListInsert(SeqList* s, int pos, DataType x)
{
assert(s);
SeqListCheckCapacity(s);
if (pos<0 || pos>s->size)
{
printf("插入位置不存在\n");
exit(1);
}
else if(pos==s->size)
{
s->a[s->size] = x;
s->size++;
}
else
{
int i = 0;
for (i = s->size - 1; i >= pos; i--)
{
s->a[i + 1] = s->a[i];
}
s->a[pos] = x;
s->size++;
}
}
5.8シーケンステーブルの任意の場所を削除します
void SeqListErase(SeqList* s, int pos)
{
assert(s);
if (s->size == 0)
{
printf("当前顺序表为空,删除失败\n");
exit(1);
}
if (pos<0||pos>s->size-1)
{
printf("要删除的位置不存在\n");
exit(1);
}
else
{
int i = 0;
for (i = pos; i <= s->size - 2; i++)
{
s->a[i] = s->a[i + 1];
}
s->size--;
}
}
6.オンライン0j練習
1つ:要素を削除します(バックルを強制します)
配列numsと値valが与えられた場合、値がvalと等しいすべての要素を削除し、削除された配列の新しい長さを返す必要があります。
余分な配列スペースを使用する代わりに、O(1)の余分なスペースのみを使用し、入力配列を適切に変更する必要があります。
要素の順序は変更できます。新しい長さを超える配列内の要素を考慮する必要はありません。
例一:
入力:nums = [0,1,2,2,3,0,4,2]、val = 2
出力:5、nums = [0,1,4,0,3]
説明:関数は新しいものを返す必要があります長さ5で、numsの最初の5つの要素は0、1、3、0、4です。これらの5つの要素は任意の順序にすることができることに注意してください。新しい長さを超える配列内の要素を考慮する必要はありません。
アイデア:2つのポインターを使用します。1つは配列をトラバースし、もう1つはデータを格納する場所を指します。
追加のスペースを申請できる場合は、通常、これを行うことができます。新しい配列スペースを申請して、非値の値のデータを格納します。実際、この新しいスペースでは、nums配列の元のスペースを新しいスペースとして直接使用でき、nums配列を1回トラバースするだけで済みます。
int removeElement(int* nums, int numsSize, int val)
{
int i = 0;
int j = 0;
for(i=0;i<numsSize;i++)
{
if(nums[i]!=val)
{
nums[j]=nums[i];
j++;
}
}
return j;
}
2. 2つの順序付けられたアレイをマージします(フォースバックル)
降順ではない2つの整数配列nums1とnums2と、それぞれnums1とnums2の要素数を表す2つの整数mとnが与えられます。
nums2をnums1にマージして、マージされた配列も降順ではない順序で配置されるようにしてください。
注:最終的に、マージされた配列は関数によって返されるのではなく、配列nums1に格納されます。この状況に対処するために、nums1の初期の長さはm + nです。ここで、最初のm個の要素はマージする必要のある要素を表し、最後のn個の要素は0であり、無視する必要があります。nums2の長さはnです
例一
入力:nums1 = [1,2,3,0,0,0]、m = 3、nums2 = [2,5,6]、n = 3
出力:[1,2,2,3,5,6]
説明:[1,2,3]と[2,5,6]を組み合わせる必要があります。
結合された結果は[1,2,2,3,5,6]であり、nums1の要素は太字のイタリックでマークされています。
アイデア:後ろから前に、nums1とnums2の数字が大きい方に配置します。(参考1)
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
int end1 = m-1;
int end2 = n-1;
int k = m + n -1;
while(end1>=0 && end2>=0)
{
if(nums1[end1] >= nums2[end2])
{
nums1[k]=nums1[end1];
k--;
end1--;
}
else
{
nums1[k]=nums2[end2];
k--;
end2--;
}
}
while(end2>=0)
{
nums1[k]=nums2[end2];
k--;
end2--;
}
}