個人ホームページ:みなさん、ようこそ->砂漠の下のコトカケヤナギ
みんな、あなたはとても美しいです
記事が役に立ったら
ワンクリックでブロガーをサポートできます
あなたの懸念のすべてのオンスは私が忍耐するための原動力です
☄: この問題の焦点:線形テーブルのシーケンステーブル
皆さんが幸せな勉強をして、毎日働いてくれることを願っています。
線形テーブルとは何ですか?
線形リストは、同じ特性を持つn個のデータ要素の有限シーケンスです。線形テーブルは、実際に広く使用されているデータ構造であり、一般的な線形テーブル:シーケンステーブル、リンクリスト、スタック、キュー、文字列...線形テーブルは論理的に線形構造、つまり連続した直線です。ただし、物理構造は必ずしも連続的ではありません。線形テーブルを物理的に格納する場合、通常は配列とチェーン構造の形式で格納されます。
シーケンステーブルとは何ですか?
シーケンステーブルは、データ要素が連続した物理アドレスを持つストレージユニットのセグメントに順次格納される線形構造であり、通常は配列ストレージを使用します。アレイでの完全なデータの追加、削除、検索、および変更。シーケンステーブルは、一般的に次のように分割できます。
1.静的順序テーブル:固定長配列を使用して要素を格納します。(固定長)
2.動的シーケンステーブル:動的に開発されたアレイストレージを使用します。(拡張可能)
1.マルチファイルプロジェクトを作成します
複数のファイルを介してシーケンステーブルを実装したいと思います。
ヘッダーファイルと関数の実装が必要です。Cファイルとテストソースファイル。
その中で、ヘッダーファイルには、ヘッダーファイルの繰り返しインクルードやヘッダーファイルの参照を防ぐ必要があります。
2.構造を作成します
シーケンステーブル関連の操作を保存して実行するための構造を作成したいと思います。
typedef int SLdataType; typedef struct Seqlist { SLdataType *a; int size; int capicity; }SL;
構造体を作成し、構造体の名前を変更しました。
次に、動的に割り当てられたメモリを使用する必要があるため、動的に割り当てられた配列を格納するためのポインタ変数が必要です。
次に、保存されている要素の数と実際の容量がわかります。
最後に、どの配列を格納するかを検討する必要がありますか?整数、文字、浮動小数点ですか?これらは不確実であるため、配列をより便利に維持できるように、型を再定義する必要があります。
3.アレイを初期化します
配列があるので、最初に行うことは配列を初期化することです。
void SLInit(SL* ps) { assert(ps); ps->a = NULL; ps->capicity = ps->size = 0; }
関数の宣言はヘッダーファイルに配置する必要があり(詳細は後で説明しません)、関数の実装は.cファイルに配置する必要があることを知っておく必要があります。
次に、関数の「予防的」プログラミングを実行する必要があります。これは、着信関数ポインターの「合法性」を判断することです。
4.ダイナミックスペースを開く(容量を増やす)
私たちの最も重要な動的配列はまだありませんか?
開発してから、mallocまたは他の方法でオープンしたいですか?
mallocが開発された後、容量拡張の問題を考慮する必要があるため、reallocを直接使用して開発するのは良いことではありません。
したがって、次のように開きます。
void SLCheckCapaticy(SL *ps) { assert(ps); if (ps->size == ps->capicity) { //使用双目操作符让增容和初始化一个realloc函数实现。 int newCapicity = ps->capicity == 0 ? 4 : 2 * (ps->capicity); SLdataType * tmp = (SLdataType *)realloc(ps->a, sizeof(SLdataType)*newCapicity); if (NULL == tmp) { perror("realloc:"); exit(-1); } ps->a = tmp; ps->capicity = newCapicity; } }
このように、機能を利用して、スペースを開放し、容量を増やすプロセスを実現できます。
5.テーブルフッターの順次挿入
テール補間関数の実装は比較的簡単ですが、注意すべきことの1つは、容量を増やすかどうかを判断することです。
void SLPushBack(SL* ps, SLdataType x) { assert(ps); SLCheckCapaticy(ps); ps->a[ps->size] = x; ps->size++; }
最初に関数のポインタが空かどうかを判断し、次に容量を増やすかどうかを判断し、最後にデータを直接配置します。
6.シーケンステーブルのテール削除
テールを削除する場合、削除する値を0または-1に設定する必要がありますか?
答えはノーです。データが元々0または1だった場合、データは変更されていないのでしょうか。
したがって、構造内の要素の数を-1にする必要があります。
void SLPopBack(SL *ps) { assert(ps); assert(ps->size); ps->size--; }
7.シーケンステーブルのヘッダー
シーケンステーブルの先頭挿入は、添え字が0の位置に書き込むことです。まず、サイズ番号として、0から添え字までの添え字を配置する必要があります。
データサイズのスペースを後方に移動すると、下付き文字0のスペースが解放されます。したがって、データを移動する必要があります。
そして、データを後ろから前に移動する必要があります。
まず、変数を添え字として作成します。
この添え字は範囲外にすることはできず、0〜size-1の要素にアクセスする必要があります。これはループ条件です。
次に、境界を越えるのではなく、拡張の問題を考慮することです。
最後に、要素size++を配置します。これで完了です。
void SLPushFront(SL *ps, SLdataType x) { assert(ps); SLCheckCapaticy(ps); int end = ps->size - 1; while (end >= 0) { ps->a[end+1] = ps->a[end]; end--; } ps->a[0] = x; ps->size++; }
8.シーケンステーブルのヘッダーを削除します
ヘッダーの削除はヘッダーの挿入に似ていますが、少し異なり、より多くの制限があります。
最初に行うことは、ポインタが空かどうかを確認することです。
要素の数が0以上であるかどうかを判別します(assertでアサートします)
ヘッダーの削除には要素の適用範囲のみが必要であり、要素の変更は必要ありません。
要素をカバーに移動します。(要素は0からsize-1であり、範囲外への転送を防ぎます。制約は1からszie -1です)
void SLPopFront(SL *ps) { assert(ps); assert(ps->size); int begin = 1; while (begin < ps->size) { ps->a[begin - 1] = ps->a[begin]; begin++; } ps->size--; }
9.どこにでも挿入
任意の位置に挿入されたパラメーターには、もう1つの添え字が必要です。
まず、ポインタと添え字が有効かどうかを判断する必要があります。
第二に、それが国境を越えて容量を拡大するかどうかを検討する必要があります。
次に、ヘッダープラグと同様の制限付きで、データ移動が実行されます。(pos to size -1、実際にはpos to sizeにアクセスします)
最後にデータを入れます、size ++
void SLInsert(SL* ps, int pos, SLdataType x) { assert(ps); assert(pos >= 0 && pos <= ps->size); SLCheckCapaticy(ps); int end = ps->size - 1; while (end >= pos) { ps->a[end + 1] = ps->a[end]; end--; } ps->a[pos] = x; ps->size++; }
10.10。どこでも削除
任意の位置を削除することは、パラメータを挿入することと同じです。
拡張を検討する必要はありませんが、前進することを検討する必要があります
データの移動:制約は(サイズに対する位置-1、サイズに対する実際のアクセス位置)です。
最後に、サイズを入れてください-。
void SLErase(SL *ps, int pos) { assert(ps); assert(pos >= 0 && pos < ps->size); int begin = pos; while (begin < ps->size-1) { ps->a[begin] = ps->a[begin+1]; begin++; } ps->size--; }
11、シーケンステーブルの検索
見つけるコードは非常に単純で、トラバースするだけで見つけることができます。
返されるのは、見つかったデータの添え字であることに注意してください。
int SLFind(SL *ps, SLdataType x) { assert(ps); for (int i = 0; i < ps->size; i++) { if (ps->a[i] == x) { return i; } } return -1; }
12.シーケンステーブルのデータ変更
変更も非常に簡単で、データを直接上書きできます。
添え字には制約があることに注意してください。1
void SLModify(SL *ps, int pos, SLdataType x) { assert(ps); assert(pos >= 0 && pos < ps->size); ps->a[pos] = x; }
13.補足の下の削除および変更部分
シーケンステーブルを検索して変更すると、データを入力するときに関数にカプセル化できます。
注意すべき点の1つは、ルックアップ関数の戻り値を判断の条件として使用でき、チェーンとしてアクセスできることです。
void Find(SL *ps)//查找相关的函数 { printf("请输入要查找的数据:"); int a = 0; scanf("%d", &a); if (SLFind(ps, a) >= 0) { printf("找到了,下标是:%d\n", SLFind(ps, a)); SLPrint(ps); } else { printf("找不到\n"); } } void Modify(SL *ps)//修改相关的函数 { printf("要查找的数据和要替换的数据:"); int x = 0; int y = 0; scanf("%d%d", &x, &y); if (SLFind(ps, x) >= 0) { SLModify(ps, SLFind(ps, x), y); printf("修改成功\n"); SLPrint(ps); } else { printf("没找到:%d\n", x); } }
14頭の削除と尾の削除、頭の挿入と尾の挿入の最適化
すでに任意の位置への挿入について書いていますが、頭の挿入と尾の挿入、頭の削除と尾の削除を最適化できますか?
ヘッダ:
void SLPushFront(SL *ps, SLdataType x) { //assert(ps); //SLCheckCapaticy(ps); //int end = ps->size - 1; //while (end >= 0) //{ // ps->a[end+1] = ps->a[end]; // end--; //} //ps->a[0] = x; //ps->size++; SLInsert(ps, 0, x);//从0下标插入 }
テールプラグ:
void SLPushBack(SL* ps, SLdataType x) { assert(ps); SLCheckCapaticy(ps); ps->a[ps->size] = x; ps->size++; //SLInsert(ps, ps->size, x);//从size位置插入,不会越界 }
ヘッダーの削除:
void SLPopFront(SL *ps) { assert(ps); assert(ps->size); int begin = 1; while (begin < ps->size) { ps->a[begin - 1] = ps->a[begin]; begin++; } ps->size--; //SLErase(ps, 0);//从0下标开始删 }
尾の削除:
void SLPopBack(SL *ps) { assert(ps); assert(ps->size); ps->size--; //SLErase(ps, ps->size - 1);//删除size-1位置的数据 }
これはコードの再利用性です。
16.空きスペースを空けて印刷
言うべきことがない:
void SLPrint(SL *ps) { assert(ps); for (int i = 0; i < ps->size; i++) { printf("%d ", ps->a[i]); } printf(" %d", ps->size); printf("\n"); }
void SLDestory(SL *ps) { assert(ps); if (ps->a != NULL) { free(ps->a); ps->a = NULL; ps->capicity = ps->size = 0; } }
17:全体的なコードについて
Seqlist.hファイル
#pragma once #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <assert.h> typedef int SLdataType; typedef struct Seqlist { SLdataType *a; int size; int capicity; }SL; void SLInit(SL* ps);//初始化 void SLCheckCapaticy(SL *ps);//增容 void SLPrint(SL *ps);//打印 void SLDestory(SL *ps);//free空间 void SLPushBack(SL* ps,SLdataType x);//尾插 void SLPopBack(SL *ps);//尾删 void SLPushFront(SL *ps,SLdataType x);//头插 void SLPopFront(SL *ps);//头删 void SLInsert(SL* ps, int pos, SLdataType x);//任意位置插入 void SLErase(SL *ps, int pos);//任意位置删除 int SLFind(SL *ps, SLdataType x);//查找 void Find(SL *ps); void SLModify(SL *ps, int pos, SLdataType x);//修改 void Modify(SL *ps);
Seqlist.cファイル
#include "Seqlist.h" void SLPrint(SL *ps) { assert(ps); for (int i = 0; i < ps->size; i++) { printf("%d ", ps->a[i]); } printf(" %d", ps->size); printf("\n"); } void SLInit(SL* ps) { assert(ps); ps->a = NULL; ps->capicity = ps->size = 0; } void SLCheckCapaticy(SL *ps) { assert(ps); if (ps->size == ps->capicity) { int newCapicity = ps->capicity == 0 ? 4 : 2 * (ps->capicity); SLdataType * tmp = (SLdataType *)realloc(ps->a, sizeof(SLdataType)*newCapicity); if (NULL == tmp) { perror("realloc:"); exit(-1); } ps->a = tmp; ps->capicity = newCapicity; } } void SLPushBack(SL* ps, SLdataType x) { assert(ps); SLCheckCapaticy(ps); ps->a[ps->size] = x; ps->size++; //SLInsert(ps, ps->size, x); } void SLPushFront(SL *ps, SLdataType x) { //assert(ps); //SLCheckCapaticy(ps); //int end = ps->size - 1; //while (end >= 0) //{ // ps->a[end+1] = ps->a[end]; // end--; //} //ps->a[0] = x; //ps->size++; SLInsert(ps, 0, x); } void SLPopBack(SL *ps) { assert(ps); assert(ps->size); ps->size--; //SLErase(ps, ps->size - 1); } void SLPopFront(SL *ps) { assert(ps); assert(ps->size); int begin = 1; while (begin < ps->size) { ps->a[begin - 1] = ps->a[begin]; begin++; } ps->size--; //SLErase(ps, 0); } void SLDestory(SL *ps) { assert(ps); if (ps->a != NULL) { free(ps->a); ps->a = NULL; ps->capicity = ps->size = 0; } } void SLInsert(SL* ps, int pos, SLdataType x) { assert(ps); assert(pos >= 0 && pos <= ps->size); SLCheckCapaticy(ps); int end = ps->size - 1; while (end >= pos) { ps->a[end + 1] = ps->a[end]; end--; } ps->a[pos] = x; ps->size++; } void SLErase(SL *ps, int pos) { assert(ps); assert(pos >= 0 && pos < ps->size); int begin = pos; while (begin < ps->size-1) { ps->a[begin] = ps->a[begin+1]; begin++; } ps->size--; } int SLFind(SL *ps, SLdataType x) { assert(ps); for (int i = 0; i < ps->size; i++) { if (ps->a[i] == x) { return i; } } return -1; } void SLModify(SL *ps, int pos, SLdataType x) { assert(ps); assert(pos >= 0 && pos < ps->size); ps->a[pos] = x; }
18:使用された知識について:
以下の知識がよくわからない兄弟の方は、編集者本人が書いた下のリンクをクリックしてください。
ポインタ関連の知識----->ポインタの知識
メモリ管理の知識->メモリ管理
構造関連の知識------->構造の知識
次の通知:
次号では、関数スタックフレームの呼び出しについて説明します。
次号は大きなものです〜!〜!〜!