データ構造とアルゴリズムの概要
1. データ構造とは何ですか?
データ構造は、コンピューターがデータを保存および整理する方法です。(相互に 1 つ以上の特定の関係を持つデータ要素のコレクション)
2. アルゴリズムとは何ですか?
アルゴリズムは、入力データを出力結果に変換するために使用される一連の計算ステップです。(アルゴリズムとは、1 つまたは値のグループを入力し、出力として 1 つまたは値のグループを生成する優れた計算プロセスです)
3. データ構造とアルゴリズムを学ぶ方法
今日の企業は学生にますます高度なコーディング能力を要求しており、データ構造やアルゴリズムに関する質問はますます難しくなっています。アルゴリズムの能力は短期間で向上するものではなく、アルゴリズムのトレーニングを積み重ねる必要があります。学校の採用活動では筆記試験が非常に難しく、就職するためにはデータ構造やアルゴリズムを早い段階から準備し、よりアルゴリズム能力を鍛える必要があります。
データ構造やアルゴリズムは初心者にとっては難しいものです。しかし、古いことわざにあるように、世の中に難しいことは何もなく、やる気のある人だけがそれを行うことができます。データ構造やアルゴリズムがどれほど難しくても、私たちはそれらを一生懸命に学ばなければなりません。もっと学び、もっと実践すればするほど、データ構造とアルゴリズムを学ぶのはどんどん簡単になっていくと私は信じています。
4. アルゴリズムの時間計算量と空間計算量
時間と空間の2 つの次元でアルゴリズムの品質を測定できます。
4.1 アルゴリズムの効率
アルゴリズムが実行可能プログラムに書き込まれた後、プログラムを実行するにはスペース リソースと時間リソースが必要になります。したがって、アルゴリズムの品質の測定は、一般に、時間計算量と空間計算量という、時間と空間の 2 つの次元から測定されます。
時間計算量は主にアルゴリズムの実行速度を測定し、空間計算量は主にアルゴリズムの実行時に必要な追加スペースを測定します。(コンピュータ開発の初期には、コンピュータの記憶容量は非常に小さく、スペースの複雑さについて非常に懸念していました。しかし、コンピュータ産業の急速な発展後、コンピュータの記憶容量は非常に高いレベルに達しました。今日は特に注意する必要があります (アルゴリズムの空間複雑さ)
4.2 ビッグオーの漸近表現
Big O 記法: 関数の漸近的な動作を記述するために使用される数学的記法
Big O の漸近記法の導出方法:
1. 実行時のすべての加算定数を定数 1 に置き換えます。
2. 実行数関数では、最上位の項のみが保持されます。
3. 最高価格の商品が存在し、それが 1 でない場合、この商品に乗じた定数を削除すると、結果はビッグ O 注文になります。
アルゴリズムの時間計算量には、最良のケース、平均的なケース、最悪のケースがあります。
最良のケース: 任意の入力サイズの最大実行数 (上限)
平均ケース: 任意の入力サイズの予想される実行数
最悪のケース: 任意の入力サイズの最小実行数 (下限)
例: 長さ N の配列内のデータ x を検索します。
最良のケース: 1 回見つかった
平均的なケース: N/2 回見つかった
最悪のケース: N 回見つかった
実際には、アルゴリズムの最悪のシナリオに焦点を当てます。したがって、配列内のデータを検索する時間計算量は O(N) です。
4.3 時間計算量
時間計算量の定義:
アルゴリズムの実行にかかる時間は理論的に計算できません。マシン上でプログラムを実行することによってのみ、消費時間を知ることができます。アルゴリズムにかかる時間は、そのステートメントの実行回数に比例し、アルゴリズムの基本操作の実行回数がアルゴリズムの時間計算量となります。
ケース 1:
基本ステートメントの数式と問題サイズ n を見つけて、アルゴリズムの時間計算量を計算します。
//计算++count语句执行的次数
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int count = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
++count;
}
for (int i = 0; i < 2 * n; i++)
{
++count;
}
int m = 10;
while (m--)
{
++count;
}
printf("%d\n", count);
return 0;
}
基本演算の数:
F(n)=n^2+2*n+10
- n=10 F(n)=130
- n=100 F(n)=10210
- n=1000 F(n)=1002010
Big O の漸近表現を使用すると、時間計算量は O(N^2) になります。
- n=10 F(n)=100
- n=100 F(n)=10000
- n=1000 F(n)=1000000
実際には、時間計算量を計算するとき、必ずしも正確な時間計算量を計算するわけではなく、おおよその実行数のみを計算します。ここでは Big O の漸近表現を使用します。
以上より、Big O の漸近表現は結果に影響の少ない項目を削除し、実行回数を簡潔明瞭に表現していることが分かります。
ケース 2:
计算Fun2的时间复杂度
void Fun2()
{
int N;
scanf("%d", &N);
int count = 0;
for (int i = 0; i < 2 * N; i++)
{
++count;
}
int M = 10;
while (M--)
{
++count;
}
printf("%d\n", count);
}
Fun2 の時間計算量は次のとおりです。
F(N)=2*N+10
ビッグ O の漸近表現: 時間計算量は O(N)
ケース 3:
//计算Fun3的时间复杂度
void Fun3()
{
int N, M;
scanf("%d%d", &N, &M);
int count = 0;
for (int i = 0; i < N; i++)
{
++count;
}
for (int j = 0; j < M; j++)
{
++count;
}
printf("%d\n", count);
}
Fun2 の時間計算量は次のとおりです:
F(N)=N+M
ビッグ O の漸近表現: 時間計算量は O(N)
ケース 4:
//二分查找的思想
void Fun4()
{
int m = 0;
int arr[10] = {
1,2,4,6,8,11,55,66,77,88};
int n;
printf("请输入要查找的数:\n");
scanf("%d", &n);
int begin = 0;
int end = 9;
while (begin <= end)
{
int mid = begin + (end - begin)/2;
if (arr[mid] < n)
begin = mid + 1;
else if (arr[mid] > n)
end = mid - 1;
else
{
printf("找到了\n");
printf("%d", arr[mid]);
m = 1;
break;
}
}
if(m==0)
printf("没找到\n");
}
インターバルデータ数:
N
N/2
N/2/2
…………
N/2/2/2……/2=1
最悪の場合、検索間隔のスケーリングに値が 1 つしか残っていない場合は問題があり、
x 回検索するとします (2^x=N なので、x=logN)。
Big O の漸近表現: 時間計算量は O(logN) です。
ケース 5:
//斐波那契递归的复杂度
#include <stdio.h>
int Fun5(size_t n)
{
if (n < 3)
return 1;
return Fun5(n - 2) + Fun5(n - 1);
}
int main()
{
int n = 7;
int sum=Fun5(n);
printf("%d\n", sum);
return 0;
}
出力結果:
再帰展開グラフ:関数再帰グラフによる
1 回 (2^ 0)
2 回 (2^ 1)
4 回 (2^ 2)
8 回 (2^ 3)
...
2^ (N-1) 回
分析 基本的な操作は 2 ^N-1 回再帰的であり、
ビッグ O の漸近表現: 時間計算量は O (2 ^N) です。
4.4 空間の複雑さ
スペース複雑さの定義:
アルゴリズムが動作中に一時的に占有するストレージスペースの量の尺度。(空間複雑度は変数の数で計算されます)
注:
関数の実行時に必要なスタック空間 (関数、ローカル変数、一部のレジスタ情報などの格納) はコンパイル時に決定されるため、空間複雑度は主に関数の実行時に要求される追加スペースによって決まります。
ケース 1:
//计算BubbleSort函数的空间复杂度
void BubbleSort(int* a, int n)
{
assert(a);
for (int end = n; end > 0; end--)
{
int exchange = 0;
for (int i = 1; i < n; i++)
{
if (a[i - 1] > a[i])
{
Swap(&a[i - 1], &a[i]);
exchange = 1;
}
}
//不需要循环了
if (exchange == 0)
break;
}
}
一定量の追加スペースが使用されるため、スペースの複雑さは O(1) であることがわかります。
ケース 2:
//看返回斐波那契数列的前n项,计算Fibonac的空间复杂度
int* Fibonac(int n)
{
if (n == 0)
return NULL;
int* fibar = (int*)malloc(sizeof(int) * (n + 1));
fibar[0] = 0;
fibar[1] = 1;
for (int i = 2; i <= n; i++)
{
fibar[i] = fibar[i - 1] + fibar[i - 2];
}
return fibar[i];
}
n+1 個の空間を動的に開き、大きな O の漸近表現は O(N) です。