データ構造:シーケンシャルテーブル(C実装)

ここに画像の説明を挿入

個人ホームページShuiyuemengjinghua
個人コラムC言語データ構造



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--;
}

要約する

以上がシーケンステーブルの実装です。ご協力ありがとうございます!

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/li209779/article/details/131955149