技術共有

データ構造 (パート 2) -- 線形テーブル

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

目次

1. 基本的な考え方

2. 線形テーブルの基本操作

3. シーケンステーブル

(1).静的割り当て

(2).動的割り当て

(3). シーケンステーブルの挿入と削除(静的割り当てを例にします)(サンプルコードには必要な基本的な関数が含まれています)

(4). ビット順で検索、値で検索

4. リンクリスト

(1).単一リンクリスト

i. 単一リンクリスト(リードノード)の定義


1. 基本的な考え方

線形テーブル:

(1).その中の各要素、同じデータ型

(2).要素間、順番に

(3) すべて。ヘッダー要素そして末尾要素

(4).ヘッダーとフッターを除き、各要素ごとに 1 つずつ見つかります。直接前駆体そして直接の後継者

2. 線形テーブルの基本操作

テーブルゼロから

初期化リスト(&L):初期化線形テーブル

リストを破棄(&L):破壊する

リスト挿入(&L, i, e):入れる、テーブル L の i 番目の位置に要素 e を挿入します。

リスト削除(&L, i, &e):消去、テーブル L の i 番目の要素を削除し、e を使用して削除された要素を返します。

LocateElem(L, e): を押します価値検索、テーブル内の特定のキーワード e の要素を見つけ、添え字ではなく e の順序を返します。

GetElem(L, i): を押します。少しテーブル内の i 番目の要素の値を検索して取得します。

その他の一般的な操作:

長さ(L): 検索テーブルリーダー過ごす

印刷リスト(L):出力テーブル全て要素

空(L):判定テーブル空いてますか?、trueまたはfalseを返します

高度に要約された、つまり売上の作成と追加、削除、変更、確認

3. シーケンステーブル

による順次ストレージデータの線形表

(1).静的割り当て

  1. #define MAX 10
  2. //顺序表(静态分配)
  3. class SqList
  4. {
  5. public:
  6. int data[MAX];
  7. int length;
  8. };
  9. //初始化
  10. void InitList(SqList &l)
  11. {
  12. for(int i = 0 ;i < 10 ;i++)
  13. {
  14. l.data[i] = 0;
  15. }
  16. l.length = 0;
  17. }
  18. //打印所有元素
  19. void PrintList(SqList &l)
  20. {
  21. for (int i = 0; i < 10; i++)
  22. cout << "第" << i << "个数:" << l.data[i] << endl;
  23. }
  24. //测验
  25. void test01()
  26. {
  27. SqList l;
  28. InitList(l);
  29. PrintList(l);
  30. }

(2).動的割り当て

  1. #define InitSize 10
  2. //顺序表(动态分配)
  3. class SqList
  4. {
  5. public:
  6. int* data; //指示动态分配数组的指针
  7. int MaxSize; //指示最大容量
  8. int length; //指示当前长度
  9. };
  10. //初始化顺序表
  11. void InitList(SqList& l)
  12. {
  13. l.data = new int[InitSize];
  14. l.MaxSize = InitSize;
  15. l.length = 0;
  16. for (int i = 0; i < l.MaxSize; i++)
  17. {
  18. l.data[i] = 0;
  19. }
  20. }
  21. //增长数组空间
  22. void IncreaseSize(SqList& l, int len)
  23. {
  24. int* p = l.data; //暂存原数组中的数据
  25. l.data = new int[10 + len]; //扩展新的数组
  26. for (int i = 0; i < l.length; i++) //将原数据拷贝进新数组中
  27. {
  28. l.data[i] = p[i];
  29. }
  30. l.MaxSize = InitSize + len; //修改数组的状态数据
  31. delete p; //将p释放
  32. }
  33. //打印所有元素
  34. void PrintList(SqList& l)
  35. {
  36. for (int i = 0; i < 10; i++)
  37. cout << "第" << i << "个数:" << l.data[i] << endl;
  38. }
  39. void test01()
  40. {
  41. SqList l;
  42. InitList(l);
  43. PrintList(l);
  44. }

(3). シーケンステーブルの挿入と削除(静的割り当てを例にします)(サンプルコードには必要な基本的な関数が含まれています)

//入れる

bool ListInsert(SqList& l, int d, int e)
{
if (l.length &gt;= MAX) //まず、テーブルがいっぱいかどうか、および挿入が正当であるかどうかを判断します。
    {
cout &lt;&lt; "挿入に失敗しました。上限に達しました" &lt;&lt; endl;
false を返します。
    }
        
(d &lt; 1 || d &gt; l.length + 1)の場合
    {
cout &lt;&lt; "挿入に失敗しました。直接の先行者がありません" &lt;&lt; endl;
false を返します。
    }
for (int j = l.length; j &gt;= d; j--) //挿入ポイントの後の要素を後方に移動します
l.data[j] = l.data[j - 1];
l.data[d - 1] = e; //挿入、d は数値を参照するため、配列変換では 1 を減算する必要があります。
l.長さ++;
true を返します。
}

//消去
bool ListDelete(SqList& l, int d, int &e)
{
if (d &lt; 1 || d &gt;l.length) //削除された位置が正当かどうかを判断します
false を返します。
e = l.data[d - 1]; //削除された要素を一時的に保存します
for (int j = d; j &lt; l.length; j++) //削除された要素の後の要素を前方に移動します
l.data[j - 1] = l.data[j]; //ここでは j = d でなければなりません、j-1 は j でカバーされます、j = d-1 の場合、次のカバレッジは j がカバーされますj+1 でカバーし、最終的に j+1 がアレイの最大容量を超える可能性があります
l.長さ--;
true を返します。
}

サンプルコード

  1. #define MAX 10
  2. //顺序表(静态分配)
  3. class SqList
  4. {
  5. public:
  6. int data[MAX];
  7. int length;
  8. };
  9. //初始化
  10. void InitList(SqList& l)
  11. {
  12. for (int i = 0; i < 10; i++)
  13. {
  14. l.data[i] = 0;
  15. }
  16. l.length = 0;
  17. }
  18. //打印所有元素
  19. void PrintList(SqList& l)
  20. {
  21. for (int i = 0; i < 10; i++)
  22. cout << "第" << i << "个数:" << l.data[i] << endl;
  23. }
  24. //存入数据
  25. void InputElem(SqList& l, int e)
  26. {
  27. int i = 0;
  28. while (i < MAX)
  29. {
  30. if (l.data[i] == 0)
  31. {
  32. l.data[i] = e;
  33. l.length++;
  34. break;
  35. }
  36. i++;
  37. }
  38. }
  39. //获取顺序表长度
  40. int GetLength(SqList l)
  41. {
  42. //cout << l.length << endl;
  43. return l.length;
  44. }
  45. //插入
  46. bool ListInsert(SqList& l, int d, int e)
  47. {
  48. if (l.length >= MAX) //首先要判断表是否已满、插入是否合法
  49. {
  50. cout << "插入失败,已达上限" << endl;
  51. return false;
  52. }
  53. if (d < 1 || d > l.length + 1)
  54. {
  55. cout << "插入失败,无直接前驱" << endl;
  56. return false;
  57. }
  58. for (int j = l.length; j >= d; j--) //将插入点之后的元素后移
  59. l.data[j] = l.data[j - 1];
  60. l.data[d - 1] = e; //插入,因为d指的是第几个数,在数组的换算中要减一
  61. l.length++;
  62. return true;
  63. }
  64. //删除
  65. bool ListDelete(SqList& l, int d, int &e)
  66. {
  67. if (d < 1 || d >l.length) //判断删除的位置是否合法
  68. return false;
  69. e = l.data[d - 1]; //暂存删除掉的元素
  70. for (int j = d; j < l.length; j++) //将被删除元素之后的元素前移
  71. l.data[j - 1] = l.data[j]; //此处,必须是j = d,j-1被j覆盖,若j = d-1,则下文的覆盖会变为j 被j+1 覆盖,而j+1在最后有可能会超过数组的最大容量
  72. l.length--;
  73. return true;
  74. }
  75. //查看情况
  76. void CheckList(SqList& l)
  77. {
  78. PrintList(l);
  79. cout << "当前长度为" << GetLength(l) << endl;
  80. }
  81. //测验
  82. void test01()
  83. {
  84. SqList l;
  85. InitList(l);
  86. //输入部分数据
  87. InputElem(l, 1);
  88. InputElem(l, 2);
  89. InputElem(l, 3);
  90. InputElem(l, 4);
  91. CheckList(l);
  92. //开始插入
  93. if(ListInsert(l, 3, 6))
  94. CheckList(l);
  95. //开始删除
  96. int a = -1;
  97. if (ListDelete(l, 2, a))
  98. CheckList(l);
  99. }

(4). ビット順で検索、値で検索

非常にシンプルなので、詳細を説明する必要はありません

  1. //判断d的合法性
  2. bool JugdeD(SqList l, int d)
  3. {
  4. if (d < 1 || d > l.length)
  5. return false;
  6. return true;
  7. }
  8. //按位序查找
  9. int GetElem(SqList l, int d)
  10. {
  11. if (JugdeD(l, d))
  12. return l.data[d - 1];
  13. return 0;
  14. }
  15. //按值查找
  16. int LocateElem(SqList l, int e)
  17. {
  18. for (int i = 0; i < l.length; i++)
  19. {
  20. if (l.data[i] == e) //数组储存的数据,若是类等复杂的数据类型,则需要对等号进行重载
  21. return i + 1;
  22. }
  23. return 0;
  24. }
  25. //其余代码与上文相同
  26. //其中,JugdeD函数可以替换上文插入与删除中对位序合法性的判别————封装

4. リンクリスト

によるチェーンストレージデータの線形表

(1).単一リンクリスト

i. 単一リンクリスト(リードノード)の定義

  1. //单链表
  2. class LNode
  3. {
  4. public:
  5. int data; //数据域,存放数据
  6. LNode* next; //指针域,指向下一个节点
  7. };
  8. //用using关键字给类起别名,用LinkList指代的是头结点,代表的是整个链表
  9. using LinkList = LNode*;
  10. //初始化
  11. bool InitList(LinkList& L)
  12. {
  13. L = new LNode();
  14. if (L == nullptr) //如果成立,则说明内存不足,分配失败
  15. return false;
  16. L->next = nullptr;
  17. return true;
  18. }

ii. 挿入と削除(先頭ノード)

ヘッド ノードがない場合は、ヘッド ポインタの変化に注目してください。他はすべて同じです。

インサート(通常版)

  1. //插入
  2. bool ListInsert(LinkList& L, int i, int e)
  3. {
  4. if (i < 1) //判断插入位点是否合法[1]——i值的合法性
  5. {
  6. cout << "i为负数" << endl;
  7. return false;
  8. }
  9. LNode* p = L; //让p与L指向相同的位点,L是指示头指针的,所以L是不能改变的
  10. LNode* s = new LNode(); //新的数据储存
  11. s->data = e;
  12. while (p != nullptr && i != 1) //由头结点起始,开始遍历寻找对应位点
  13. {
  14. p = p->next;
  15. i--;
  16. }
  17. if (p == nullptr) //判断插入的位点是否合法[2]——i值对应的节点的合法性
  18. {
  19. cout << "插入位点超出实际长度" << endl;
  20. return false;
  21. }
  22. s->next = p->next; //开始接轨,顺序不能乱
  23. p->next = s;
  24. return true;
  25. }

インサート(パッケージ版)

  1. //特定节点的后插操作
  2. bool InsertNextNode(LNode* p, int e)
  3. {
  4. if (p == nullptr)
  5. {
  6. cout << "插入位点超出实际长度" << endl;
  7. return false;
  8. }
  9. LNode* s = new LNode();
  10. s->data = e;
  11. s->next = p->next;
  12. p->next = s;
  13. return true;
  14. }
  15. //插入
  16. bool ListInsert(LinkList& L, int i, int e)
  17. {
  18. if (i < 1) //判断插入位点是否合法[1]——i值的合法性
  19. {
  20. cout << "i为负数" << endl;
  21. return false;
  22. }
  23. LNode* p = L; //让p与L指向相同的位点,L是指示头指针的,所以L是不能改变的
  24. while (p != nullptr && i != 1) //由头结点起始,开始遍历寻找对应位点
  25. {
  26. p = p->next;
  27. i--;
  28. }
  29. return InsertNextNode(p, e); //被封装了的部分
  30. }