banner
cos

cos

愿热情永存,愿热爱不灭,愿生活无憾
github
tg_channel
bilibili

データ構造学習ノート<1> 線形リスト

一、線形リストの抽象データ型の説明#

タイプ名:線形リスト(List)
データオブジェクト集合:線形リストは n (>=0) 個の要素から構成される順序列 (a1,a2,……,an)
操作集合:線形リスト L∈List, 整数 i は位置を示し、要素 X∈ElementType

二、順序リスト#

1. 定義#

struct LNode {
    ElementType Data[MAXSIZE];//最大でMAXSIZE個の要素を格納できる配列
    int Last;//最後の要素のインデックス!
};
typedef struct LNode *List;

インデックス i の要素にアクセスする:L.Data [i] または PtrL->Data [i]
線形リストの長さ:L.Last+1 または PtrL->Last+1;

2. 操作#

基本操作は以下の通りです

1.List MakeEmpty ();// 空の線形リストを初期化
2.ElementType FindKth (int K, List Ptrl);// インデックス K の要素を返す
3.int Find (ElementType X, List Ptrl);// 線形リスト L で X の最初の出現位置を探す
4.void Insert (ElementType X, int i, List Ptrl);// 位置 i の前に新しい要素 X を挿入
5.void Delete (int i, List Ptrl);// 指定された位置 i の要素を削除
6.int Length (List Ptrl);// 線形リストの長さ n を返す
**

以下、順に確認していきましょう

(1) 空のリストを作成#

List MakeEmpty() {
    List PtrL;
    PtrL = (List)malloc(sizeof(struct LNode));
    PtrL -> Last = -1;
    return PtrL;
}

(2) インデックス K の要素を探す#

インデックス K の要素を返します。

ElementType FindKth(int K, List Ptrl) {
    return Ptrl->Data[K];
}

(3) 要素 X を探す#

インデックスを返し、見つからなければ - 1 を返します。

int Find(ElementType X, List Ptrl) {
    int i = 0;
    while(i <= PtrL->Last && PtrL->Data[i] != X)
        i++;
    if(i > PtrL->Last) return -1;//見つからなければ-1を返す
    else return i;//見つかった場合は格納位置、すなわちインデックスを返す
}

(4) 挿入#

i (1 ≤ i ≤ n+1) の位置に値 X の新しい要素を挿入します。

void Insert(ElementType X, int i, List Ptrl) {
    int j;
    if(Ptrl->Last == MAXSIZE-1) {//リストが満杯の場合、挿入できません
        printf("リストが満杯です");
        return;
    }
    if(i < 1 || i > Ptrl->Last+2) {//入力が妥当か確認
        printf("位置が不正です");
        return;
    }
    for(j = Ptrl->Last; j >= i-1; j--) //ここは前から後ろに順序を変えてはいけません
        Ptrl->Data[j+1] = Ptrl->Data[j];
    Ptrl->Data[i-1] = X;
    Ptrl->Last++;//lastは最後の要素を指し続けます!
    return;
}

(5) 削除#

i 番目の要素を削除します(インデックスは i-1)。

void Delete(int i, List Ptrl) {
    int j;
    if(i < 1 || i > Ptrl->Last+1) {//入力が妥当か確認
        printf("%d番目の要素は存在しません",i);
        return;
    }
    for (j = i; j <= Ptrl->Last; j++) //削除操作は前から後ろに行う必要があります
        Ptrl->Data[j-1] = Ptrl->Data[j];
    Ptrl->Last--;
    return;
}

(6) 線形リストの長さ n を返す#

i 番目の要素を削除します(インデックスは i-1)。

int Length(List Ptrl){
    return Ptrl->Last + 1;
}

3. 完全なコードのデモ#

//順序リスト
#include <iostream>
using namespace std;
typedef int ElementType;
const int MAXSIZE = 1000;
// 1.定義部分
struct LNode {
	ElementType Data[MAXSIZE];  //最大でMAXSIZE個の要素を格納できる配列
	int Last;					//最後の要素のインデックス!
};
typedef LNode *List;
// 2.操作関数
//(1) 空の線形リストを作成
List MakeEmpty() {
	List Ptrl;									//作成
	Ptrl = new struct LNode;  //最初のノードのためのメモリを割り当て
	Ptrl->Last = -1;  //まだデータを格納していないので、-1に設定
	return Ptrl;	  //ポインタを返す
}
//(2) インデックスKの要素を探す インデックスKの要素を返す
ElementType FindKth(int K, List Ptrl) {
    return Ptrl->Data[K];
}
//(3) 要素Xを探す インデックスを返し、見つからなければ-1を返す
int Find(ElementType X, List Ptrl) {
	int i = 0;
	while (i <= Ptrl->Last && Ptrl->Data[i] != X) {
		i++;
	}
	if (i > Ptrl->Last)
		return -1;
	else
		return i;
}
//(4) 要素Xを挿入 i(1 ≤ i ≤ n+1)の位置に値Xの新しい要素を挿入します。
void Insert(ElementType X, int i, List Ptrl) {
	if (Ptrl->Last == MAXSIZE - 1) {  //リストが満杯の場合、挿入できません
		printf("リストが満杯です");
		return;
	}
	if (i < 1 || i > Ptrl->Last + 2) {  //入力が妥当か確認
		printf("位置が不正です");
		return;
	}
	int j;
	for (j = Ptrl->Last; j >= i - 1; j--)  //ここは前から後ろに順序を変えてはいけません
		Ptrl->Data[j + 1] = Ptrl->Data[j];
	Ptrl->Data[i - 1] = X;
	Ptrl->Last++;  // lastは最後の要素を指し続けます!
	return;
}
//(5) 削除 i番目の要素を削除します(インデックスはi-1)。
void Delete(int i, List Ptrl) {
	int j;
	if (i < 1 || i > Ptrl->Last + 1) {  //入力が妥当か確認
		printf("%d番目の要素は存在しません", i);
		return;
	}
	for (j = i; j <= Ptrl->Last; j++)  //削除操作は前から後ろに行う必要があります
		Ptrl->Data[j - 1] = Ptrl->Data[j];
	Ptrl->Last--;
	return;
}
//(6) 線形リストの長さnを返す
int Length(List Ptrl){
    return Ptrl->Last + 1;
}
int main() {
    List P;
    P = MakeEmpty();
    for(int i = 0; i < 10; i++){
        Insert(i,i+1,P);
    }
    cout << "この順序リストの長さは:" << Length(P) << endl;
    cout << "5番目の要素は:" << FindKth(4,P) << endl;
    cout << "--4番目の要素を削除--" << endl;
    Delete(4,P);
    cout << "削除後の5番目の要素は:" << FindKth(4,P) << endl;
    cout << "リストに要素3はありますか(あればそのインデックス、なければ-1を表示):" << Find(3,P) << endl;
    cout << "リストに要素5はありますか(あればそのインデックス、なければ-1を表示):" << Find(5,P) << endl;
    delete [] P;
    return 0;
}

出力結果:

この順序リストの長さは:10
5 番目の要素は:4
--4 番目の要素を削除 --
削除後の 5 番目の要素は:5
リストに要素 3 はありますか(あればそのインデックス、なければ - 1 を表示):-1
リストに要素 5 はありますか(あればそのインデックス、なければ - 1 を表示):4

三、線形リストの連鎖的ストレージ#

重要!!連結リストは、論理的に隣接する 2 つの要素が物理的に隣接する必要はなく、「リンク」によってデータ要素間の論理関係を構築します。
その挿入と削除はデータ要素を移動する必要はなく、リンクを変更するだけです。

1. 定義#

typedef struct LNode *List;
struct LNode {
    ElementType Data;
    List Next;//次のノードを指すポインタを格納
}L;
List PtrL;

2. 操作#

基本操作は以下の通りです

1.List Insert (ElementType X, int i, List PtrL) ;// 挿入(i-1 (1<=i<=n+1) 番目のノードの後に値 X の新しいノードを挿入)
2.List FindKth (int K, List PtrL) ;// 順序で探す、連結リストの K 番目の要素を探す
List Find (ElementType X, List PtrL) ; // 値で探す:要素 K を探す
3.List Delete (int i, List PtrL);// 削除操作(連結リストの i 番目の位置のノードを削除)
4.int Length (List PtrL)// リストの長さを求める

(1) 挿入操作#

i-1 (1 ≤ i ≤ n+1) 番目のノードの後に値 X の新しいノードを挿入します。
(1) まず新しいノードを構築し、s を指します //malloc でメモリを割り当て、s のデータ Data に X を代入
(2) 次に連結リストの i-1 番目のノードを見つけ、p を指します
(3) 次にポインタを変更し、ノードを挿入します(p の後に新しいノード s を挿入)
// まず p の元の next を s の next ポインタに設定し、次に p の next ポインタを s に設定します。

List Insert(ElementType X, int i, List PtrL) {
    List p, s;
    if(i == 1) {//新しいノードをリストの先頭に挿入
        s = (List)malloc(sizeof(struct LNode));//ノードを割り当て、データを設定
        s->Data = X;
        s->Next = PtrL;
        return s;       //新しいリストの先頭ポインタを返す
    }
    p = Find(i-1,PtrL);         //i-1番目のノードを探す
    if(p == NULL) {             //i-1番目が存在しないので挿入できない
        printf("パラメータiが間違っています");
        return NULL;
    } else {
        s = (List)malloc(sizeof(struct LNode)); //ノードを割り当て、データを設定
        s->Data = X;
        s->Next = p->Next;          //新しいノードをi-1番目のノードの後に挿入
        p->Next = s;
        return PtrL;
    }
}

(2) 探す#

見つかればそのノードを指すポインタを返し、見つからなければ NULL を返します。

1. 値で探す:Find#

値で探す:要素 K を探します。

List Find(ElementType X, List PtrL) {
    List p = PtrL;
    while(p != NULL && p->Data != X) 
        p = p->Next;
    if(p == NULL) {          
        cout << "その要素は見つかりません" << endl;
        return NULL;
    } else  return p;
}
2. 順序で探す:FindKth#

順序で探す:連結リストの K 番目の要素を探します。

List FindKth(int K, List PtrL) {
    List p = PtrL;
    int i = 1;
    while (p != NULL && i < K) {
        p = p->Next;
        i++;
    }
    if(i == K) return p;//K番目を見つけたらポインタを返す
    else {              //そうでなければNULLを返す
        cout << "その要素は見つかりません" << endl;
        return NULL;
    }
}

(3) 削除操作#

連結リストの i 番目の位置のノードを削除します。
(1) まず連結リストの i-1 番目のノードを見つけ、p を指します;//Find (i-1,PtrL);
(2) 次にポインタ s を削除されるノード(p の次のノード)を指します //s = p->Next;
(3) 次にポインタを変更し、s が指すノードを削除します //p->Next = s->Next;
(4) 最後に s が指すノードのメモリを解放します! //free (s)

List Delete(int i, List PtrL) {
    List p, s;
    if( i == 1) {   //リストの最初のノードを削除する場合
        s = PtrL;           //sは最初のノードを指します
        if (PtrL != NULL)   PtrL = PtrL->Next;  //連結リストから削除
        else return NULL;
        free(s);                            //削除されたノードを解放
        return PtrL;
    }
    p = FindKth(i-1, PtrL);     //i-1番目のノードを探す
    if (p == NULL) {
        printf("%d番目のノードは存在しません", i-1);
        return NULL;
    } else if (p->Next == NULL) {
        printf("%d番目のノードは存在しません",i);
        return NULL;
    } else {
        s = p->Next;            //sはi番目のノードを指します
        p->Next = s->Next;      //連結リストから削除
        free(s);                //削除されたノードのメモリを解放
        return PtrL;
    }
}

(4) リストの長さを求める#

int Length(List PtrL) {
    List p = PtrL;//pはリストの最初のノードを指します
    int j = 0;
    while(p) {
        p = p->Next;
        j++;
    }
    return j;
}

3. 完全なコードのデモ#

//連結リスト
#include <iostream>
using namespace std;
typedef int ElementType;
const int MAXSIZE = 1000;
// 1.定義部分
struct LNode;
typedef LNode *List;
struct LNode {
	ElementType Data;
	List Next;  //次のノードを指すポインタを格納
};
List Insert(ElementType X,int i,List PtrL);  
//挿入(i-1(1<=i<=n+1)番目のノードの後に値Xの新しいノードを挿入)
List FindKth(int K, List PtrL);  //順序で探す、連結リストのK番目の要素を探す
List Find(ElementType X, List PtrL);  //値で探す:要素Kを探す
List Delete(int i, List PtrL);  //削除操作(連結リストのi番目の位置のノードを削除)
int Length(List PtrL);			//リストの長さを求める
// 2.操作関数
//(1) 挿入操作 i-1(1 ≤ i ≤ n+1)番目のノードの後に値Xの新しいノードを挿入します。
List Insert(ElementType X, int i, List PtrL) {
	List p, s;
	if (i == 1) {			   //新しいノードをリストの先頭に挿入
		s = new struct LNode;  //ノードを割り当て、データを設定
		s->Data = X;
		s->Next = PtrL;
		return s;  //新しいリストの先頭ポインタを返す
	}
	p = Find(i - 1, PtrL);  //i-1番目のノードを探す
	if (p == NULL) {		//i-1番目が存在しないので挿入できない
		printf("パラメータiが間違っています");
		return NULL;
	} else {
		s = new struct LNode;  //ノードを割り当て、データを設定
		s->Data = X;
		s->Next = p->Next;  //新しいノードをi-1番目のノードの後に挿入
		p->Next = s;
		return PtrL;
	}
}
//(2) 探す 見つかればそのノードを指すポインタを返し、見つからなければNULLを返します。
List Find(ElementType X, List PtrL) {//値で探す:要素Xを探します。
    List p = PtrL;
    while(p != NULL && p->Data != X) 
        p = p->Next;
    if(p == NULL) {          
        cout << "その要素は見つかりません" << endl;
        return NULL;
    } else  return p;
}
List FindKth(int K, List PtrL) {//順序で探す:連結リストのK番目の要素を探します。
    List p = PtrL;
    int i = 1;
    while (p != NULL && i < K) {
        p = p->Next;
        i++;
    }
    if(i == K) return p;//K番目を見つけたらポインタを返す
    else {              //そうでなければNULLを返す
        cout << "その要素は見つかりません" << endl;
        return NULL;
    }
}
//(3) 削除 削除連結リストのi番目の位置のノードを削除します。
List Delete(int i, List PtrL) {
    List p, s;
    if( i == 1) {   //リストの最初のノードを削除する場合
        s = PtrL;           //sは最初のノードを指します
        if (PtrL != NULL)   PtrL = PtrL->Next;  //連結リストから削除
        else return NULL;
        delete [] s;                           //削除されたノードを解放
        return PtrL;
    }
    p = FindKth(i-1, PtrL);     //i-1番目のノードを探す
    if (p == NULL) {
        printf("%d番目のノードは存在しません", i-1);
        return NULL;
    } else if (p->Next == NULL) {
        printf("%d番目のノードは存在しません",i);
        return NULL;
    } else {
        s = p->Next;            //sはi番目のノードを指します
        p->Next = s->Next;      //連結リストから削除
        delete [] s;                //削除されたノードのメモリを解放
        return PtrL;
    }
}
//(4) リストの長さを求める
int Length(List PtrL) {
    List p = PtrL;//pはリストの最初のノードを指します
    int j = 0;
    while(p) {
        p = p->Next;
        j++;
    }
    return j;
}
int main() {
	List P = NULL;
	for (int i = 0; i < 10; i++) {
		P = Insert(i, 1, P);// 先頭挿入法でリストの先頭に要素を挿入
	}
    List s;
	cout << "この連結リストの長さは:" << Length(P) << endl;
	cout << "4番目の要素は:";
    s = FindKth(4, P);
    if(s) cout << s->Data << endl;
	cout << "--4番目の要素を削除--" << endl;
	Delete(4, P);
	cout << "削除後の4番目の要素は:" ;
    s = FindKth(4, P);
    if (s) cout << s->Data << endl;
	cout << "リストに要素6はありますか:" ;
    s = Find(6, P);
    if (s) cout << s->Data << endl;
	cout << "リストに要素5はありますか:" ;
    s = Find(5, P);
    if (s) cout << s->Data << endl;
	delete[] P;
	return 0;
}

出力結果:

この連結リストの長さは:10
4 番目の要素は:6
--4 番目の要素を削除 --
削除後の 4 番目の要素は:5
リストに要素 6 はありますか:その要素は見つかりません
リストに要素 5 はありますか:5

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。