シーケンス構造の基本的な理解
定義: 論理
的に隣接するデータ要素を物理的に隣接するストレージ ユニットに格納するストレージ構造 (連続したストレージ ユニットを占有し、途中で空にすることはできません)
格納場所の計算:
LOC ( a ( i + 1 ) ) = LOC ( a ( i ) ) + l LOC(a(i+1))=LOC(a(i))+lL OC ( a ( i+1 ))=L OC ( a ( i ))+l
LOC ( a ( i ) ) = LOC ( a ( j ) ) + ( i − j ) l LOC(a(i))=LOC(a(j))+(ij)lL OC ( a ( i ))=L OC ( a ( j ))+(私は−j ) l
どこでlは、各要素に必要なストレージ ユニットです。
シーケンス テーブルの利点:
論理関係は隣接する物理的な位置によって表され、任意の要素にランダムにアクセスできます。
シーケンス テーブルの順次ストレージ表現:
[連続アドレス、連続格納、ランダムアクセス、同型] ==> 配列 (要素)
したがって、1 次元配列を使用してシーケンス テーブルを表すことができます。ただし、シーケンス テーブルの長さは変更できますが、配列の長さは不変であるため、追加の変数を使用してシーケンス テーブル内の現在の位置の長さを示します。
# define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
typedef struct{
ElemType elem[LIST_INIT_SIZE];
int lenth; //当前长度
}SqList
注: 論理ビット順序と物理ビット順序の差は 1 です (配列の最初の項目が [0] であるため)。
例:多項式順次記憶構造型定義
P ( x ) = A xa + B xb + C xc + ⋅ ⋅ + Z ( i ) xz P(x)=Ax^a+Bx^b+Cx^c+… +Z(i)x^zP ( x )=A ×a+B ×b+C ×c +····+ Z ( i ) xz
の線形テーブル
は P = ( ( A , a ) , ( B , b ) , ( C , c ) , . . , ( Z , z ) ) P = ( ( A , a ) , ( B , b ) ) , ( C , c ) , . . , ( Z , z ) )P=( ( 、a ) 、( B 、b ) 、( C 、c ) 、... ,( Z 、z ))
# define MAXSIZE 1000
typedef struct{
//多项式非零项的意义
float p; //系数
int e; //指数
}Polynomial;
typedef struct{
Polynomial *elem; //存储空间的基地址
int length; //多项式中当前项的系数
}SqList; //多项式的顺序存储结构类型为SqList
補充する
補足1:静的配列と動的配列の違い
配列の静的割り当て | 配列の動的割り当て |
---|---|
typedef構造体{ | typedef構造体{ |
ElemTypeデータ[最大サイズ] ; | **ElemType *データ; ** |
整数の長さ; | 整数の長さ; |
}SqList; //シーケンス リスト タイプ | }SqList; //シーケンス リスト タイプ |
配列の静的割り当てでは、data[maxsize] は本質的に data[0] のアドレスを格納し、ポインター *data もアドレスを格納しますが、これは本質的に同じです。配列の動的割り当ては、ストレージ スペースを適用することによって行われます。
SqList L;
L.data = (ElemType*)malloc(sizeof(ElemType)×Maxsize)
補足2:共通機能
ヘッダー ファイルをロードする必要があります: <stdlib.h>
malloc(m) 関数: m バイト長のアドレス空間を開き、この空間の最初のアドレスを返します
sizeof(x) 演算: 変数 x の長さを計算します
free§ 関数: ポインター p が指す変数の記憶域を解放します。つまり、変数を完全に削除します。
(ElemType*)malloc...: 強制型メソッド
補足 3: a と b の交換問題
パラメーターとしての参照型 (C++):
int i=5;
int&j=i;
j は参照型です。i の値が変化すると、それに応じて j の値も変化します。
たとえば、a と b を交換する関数は、次の 2 つの方法で実行できます。
| 利用指针类型 | 利用引用类型 |
| ----------------------------- | --------------------------- |
| #include <iostream.h> | #include <iostream.h> |
| void swap(float *m,float *n){
| void swap(float&m,float&n){
|
| float temp; | float temp; |
| temp = *m; | temp=m; |
| *m = *n; | m=n; |
| *n = temp; | n=temp; |
| } | } |
| void main(){
| void main(){
|
| float a,b, *p1, *p2; | float a,b; |
| cin>>a>>b; | cin>>a>>b; |
| p1=&a; p2=&b; | swap(a,b); |
| swap(p1,p2); | count<<a<<endl<<b<<endl; |
| count<<a<<endl<<b<<endl; | } |
| } | |
補足4:マクロ定義
#定義 TRUE 1
#定義 FALSE 0
#定義 OK 1
#定義エラー 0
#define INFEASIBLE -1
#define OVERFLOW -2
補足5:記憶関連
ソフトウェア | ハ | C++ |
---|---|---|
記憶を得る | malloc | 新しい |
空きメモリ | 無料 | 消去 |
基本操作の実装
線形リストの初期化: InitList(&L)
演算結果: 空の線形リスト L を構築する
C++:
子:
線形リスト破壊: DestoryList(&L)
初期条件: 線形テーブル L は既に存在します
操作結果:リニアテーブルLを破壊
C++:
子:
C(1):
線形リストをクリア: ClearList(&L)
初期条件: 線形テーブル L は既に存在します
操作結果: リニア テーブル L を空のテーブルにリセットします
C++:
子:
リニアテーブルクリア判定:ListEmpty(L)
初期条件: 線形テーブル L は既に存在します
演算結果: 線形テーブル L が空のテーブルの場合は TRUE を返し、それ以外の場合は FALSE を返します。
C++:
子:
線形テーブルの長さ: ListLength(L)
初期条件: 線形テーブル L は既に存在します
演算結果: 線形テーブル L のデータ要素の数を返す
C++:
子:
線形テーブル ルックアップ: GetElem(L,i,&e)
初期条件: 線形リスト L が既に存在する、1≤i≤ListLength(L)
演算結果: e を使用して、線形テーブル L の i 番目のデータ要素の値を返します
C++:
子:
線形テーブルの配置: LocateElem(L,e,compare())
**初期条件: **線形テーブル L は既に存在し、compare() はデータ要素の決定関数です
**演算結果:** compare() と e を満たす L の最初のデータ要素のビット シーケンスを返します。そのような要素が存在しない場合、戻り値は 0 です。
C++:
子:
アルゴリズムの分析:
予想頻度 (平均ルックアップ長) は
( 1 + 2 + 3 + 4 + 5 + 6 + ⋅ ⋅ ⋅ + n − 1 + n ) / n = ( n + 1 ) / 2 (1+2+3+ 4+5+6+・・・+n-1+n)/n=(n+1)/2( 1+2+3+4+5+6+・・・・・・・・_+ n−1+n ) / n=( n+1 ) /2
を展開します。
上図の状況は、検索確率が等しい場合の結果です。
線形テーブル要素の挿入: ListInsert(&L,i,e)
初期条件: 線形リスト L が既に存在する、1≤i≤ListLength(L)+1
演算結果:L の i 番目の位置に新しいデータ要素 e を挿入し、L の長さを 1 増やします。
アルゴリズム思考:
1) 挿入位置 i が正当かどうかを判断します。
2) シーケンス テーブルの格納領域がいっぱいかどうかを判断し、いっぱいの場合は ERROR を返します。
子:
アルゴリズム分析:
挿入位置には、次の 3 つの状況があります。
①最後に入れると全く動く必要がなく、スピードが速い
②位置の途中に挿入する場合、一定数の要素を適度な速度で移動する必要があります
③手前に挿入すると、テーブル内のすべての要素を後ろに移動する必要があり、速度が非常に遅い
では、平均はどうでしょうか。
合計 n+1 の挿入位置があり、i 番目の挿入位置を n-i+1 回移動する必要があることがわかっているので、(
1 + 2 + 3 + 4 + 5 + 6 + ⋅ ⋅ + n − 1 + n ) / ( n + 1 ) = n / 2 (1+2+3+4+5+6+…+n-1+n)/(n+1)=n/2( 1+2+3+4+5+6+・・・・・・・・_+ n−1+n ) / ( n+1 )=n /2
線形テーブル要素の削除: ListDelete(&L,i,&e)
初期条件: 線形リスト L が既に存在する、1≤i≤ListLength(L)
演算結果:L の i 番目のデータ要素を削除し、その値を e で返し、L の長さを 1 つ減らします。
アルゴリズム思考:
① 削除位置 i が正当かどうかを判定する (正当値 1≤i≤n)
②削除する要素をeに残す
③ i+1 番目から n 番目の要素を順番に 1 つ前に移動
④テーブルの長さが1つ減り、削除成功でOKを返す
C++:
子:
アルゴリズム分析: ここでの分析は、線形テーブル要素の挿入
( 1 + 2 + 3 + 4 + 5 + 6 + ⋅ ⋅ + n − 1 ) / n = ( n − 1 ) / 2 (1 + 2+3+4+5+6+····+n-1)/n=(n-1)/2( 1+2+3+4+5+6+・・・・・・・・_+ n−1 ) / n=( n−1 ) /2
シーケンスの要約:
アドバンテージ:
・高いストレージ密度(ノード自体が占有するストレージ/ノード構造が占有するストレージ)
テーブル内の任意の要素にランダムにアクセスできます
欠点:
· 要素の挿入と削除では、多数の要素を移動する必要があります
・収納スペースの無駄
静的ストレージの形式に属し、データ要素は自由に拡張できません