가능한 한 공식적인 정의와 간단한 수학을 선호하지 않습니다.
가능한 한 공식적인 정의와 간단한 수학을 선호하지 않습니다.
답변:
참고로, 이것은 Big O 표기법 (상한)과 Theta 표기법 "Θ"(양쪽 바운드)와 혼동 될 수 있습니다. 내 경험상, 이것은 실제로 비 학술적 환경에서의 토론에서 일반적입니다. 혼란에 대한 사과.
이 그래프를 통해 큰 O 복잡성을 시각화 할 수 있습니다.
Big-O 표기법에 대한 가장 간단한 정의는 다음과 같습니다.
Big-O 표기법은 알고리즘의 복잡성을 나타내는 상대적인 표현입니다.
그 문장에는 중요하고 일부러 선택된 단어가 있습니다.
- 상대 : 사과와 사과 만 비교할 수 있습니다. 산술 곱셈을 수행하는 알고리즘을 정수 목록을 정렬하는 알고리즘과 비교할 수 없습니다. 그러나 산술 연산을 수행하는 두 알고리즘 (하나의 곱셈, 하나의 덧셈)을 비교하면 의미있는 것을 알 수 있습니다.
- 표현 : Big-O (가장 간단한 형식)는 알고리즘 간의 단일 변수 비교를 줄입니다. 해당 변수는 관찰 또는 가정에 따라 선택됩니다. 예를 들어, 정렬 알고리즘은 일반적으로 비교 작업을 기반으로 비교됩니다 (상대 순서를 결정하기 위해 두 노드를 비교). 이것은 비교가 비싸다고 가정합니다. 그러나 비교가 저렴하지만 교환이 비싸면 어떨까요? 비교를 변경합니다. 과
- 복잡성 : 10,000 개의 요소를 정렬하는 데 1 초가 걸리면 백만을 정렬하는 데 얼마나 걸립니까? 이 경우의 복잡성은 다른 것에 대한 상대적인 척도입니다.
나머지를 읽었을 때 되돌아 와서 위의 내용을 다시 읽으십시오.
내가 생각할 수있는 Big-O의 가장 좋은 예는 산술입니다. 두 개의 숫자 (123456 및 789012)를 사용하십시오. 우리가 학교에서 배운 기본 산술 연산은 다음과 같습니다.
- 부가;
- 빼기;
- 곱셈; 과
- 분할.
이들 각각은 작업 또는 문제입니다. 이를 해결하는 방법을 알고리즘 이라고합니다 .
추가가 가장 간단합니다. 숫자를 오른쪽으로 정렬하고 결과에 해당 추가의 마지막 숫자를 기록하는 열에 숫자를 추가합니다. 해당 숫자의 '수십'부분이 다음 열로 넘어갑니다.
이 숫자를 더하는 것이이 알고리즘에서 가장 비싼 연산이라고 가정 해 봅시다. 이 두 숫자를 더하기 위해서는 6 자리 숫자를 더해야합니다 (그리고 7 번째 숫자도 가능). 두 100 자리 숫자를 더하면 100을 더해야합니다. 10,000 자리 숫자를 두 개 더하면 10,000을 더해야합니다.
패턴을 보시겠습니까? 복잡성 (동작 횟수 인)는 자릿수에 정비례 N 보다 큰 수이다. 이것을 O (n) 또는 선형 복잡성이라고 합니다.
빼기는 비슷합니다 (캐리지 대신 빌려야 할 수도 있습니다).
곱셈이 다릅니다. 숫자를 정렬하고 맨 아래 숫자의 첫 번째 숫자를 가져 와서 맨 위 숫자의 각 숫자와 차례로 각 숫자를 곱합니다. 6 자리 숫자 두 개를 곱하려면 36 곱셈을해야합니다. 최종 결과를 얻으려면 10 또는 11 열을 추가해야 할 수도 있습니다.
100 자리 숫자가 두 개인 경우 10,000 곱하기와 200을 더해야합니다. 2 백만 자리 숫자의 경우 1 조 (10 12 ) 곱셈과 2 백만 더하기 를 수행해야 합니다.
알고리즘이 n 제곱으로 확장됨에 따라 이것은 O (n 2 ) 또는 2 차 복잡성 입니다. 또 다른 중요한 개념을 소개하기에 좋은시기입니다.
우리는 복잡성의 가장 중요한 부분에 대해서만 신경을 씁니다.
현명한 사람은 우리가 n 2 + 2n 의 연산 수를 표현할 수 있음을 깨달았을 것 입니다. 그러나 두 개의 숫자 (백만 자릿수)를 가진 예제에서 보았 듯이 두 번째 항 (2n)은 중요하지 않습니다 (해당 단계의 총 작업 중 0.0002 %를 차지함).
우리는 여기서 최악의 시나리오를 가정 한 것을 알 수 있습니다. 6 자리 숫자를 곱하는 동안 그 중 하나에 4 자리 숫자가 있고 다른 하나에 6 자리 숫자가 있으면 24 개의 곱셈 만 있습니다. 여전히, 우리는 그 'n'에 대한 최악의 시나리오, 즉 두 숫자가 모두 6 자리 숫자 인 경우를 계산합니다. 따라서 Big-O 표기법은 알고리즘의 최악의 시나리오에 관한 것입니다.
내가 생각할 수있는 다음으로 가장 좋은 예는 전화 번호부 (일반적으로 화이트 페이지 또는 이와 유사 함)이지만 국가마다 다릅니다. 그러나 나는 성을 기준으로 사람들을 나열 한 다음 이니셜이나 이름, 주소 및 전화 번호에 대해 이야기하고 있습니다.
이제 1,000,000 개의 이름이 포함 된 전화 번호부에서 "John Smith"의 전화 번호를 찾도록 컴퓨터에 지시 한 경우 어떻게 하시겠습니까? S가 얼마나 멀리 시작했는지 추측 할 수 없다는 사실을 무시하면 (할 수 없다고 가정) 어떻게해야합니까?
일반적인 구현은 중간 정도까지 열고 500,000 번째 를 "Smith"와 비교하는 것입니다. 그것이 "Smith, John"이라면, 우리는 정말 운이 좋았습니다. "John Smith"가 그 이름 앞이나 뒤에있을 가능성이 훨씬 더 높습니다. 그런 다음 전화 번호부의 마지막 절반을 반으로 나누고 반복하십시오. 이전의 경우 전화 번호부의 전반부를 반으로 나누고 반복합니다. 등등.
이를 이진 검색 이라고하며 이를 인식하는지 여부에 관계없이 매일 프로그래밍에 사용됩니다.
따라서 백만 개의 전화 번호부에서 이름을 찾으려면 실제로 최대 20 회 수행하여 이름을 찾을 수 있습니다. 검색 알고리즘을 비교할 때 우리는이 비교가 'n'이라고 결정합니다.
- 이름이 3 개인 전화 번호부의 경우 최대 2 개의 비교가 필요합니다.
- 7의 경우 최대 3이 걸립니다.
- 15의 경우 4가 걸립니다.
- …
- 1,000,000의 경우 20이 걸립니다.
정말 대단하지 않습니까?
Big-O 용어에서 이것은 O (log n) 또는 로그 복잡도 입니다. 이제 해당 로그는 ln (base e), log 10 , log 2 또는 다른 염기가 될 수 있습니다. O (2n 2 )와 O (100n 2 )가 여전히 O (n 2 ) 와 마찬가지로 여전히 O (log n)인지는 중요하지 않습니다 .
이 시점에서 Big O를 사용하여 알고리즘으로 세 가지 경우를 결정할 수 있다고 설명하는 것이 좋습니다.
- 최상의 경우 : 전화 번호부 검색에서 가장 좋은 경우는 한 번의 비교에서 이름을 찾는 것입니다. 이것은 O (1) 또는 일정한 복잡성입니다 .
- 예상 사례 : 위에서 논의한 바와 같이 이것은 O (log n)입니다. 과
- 최악의 경우 : 이것은 또한 O (log n)입니다.
일반적으로 우리는 최선의 경우에 관심이 없습니다. 우리는 예상과 최악의 경우에 관심이 있습니다. 때로는 이들 중 하나가 더 중요 할 것입니다.
전화 번호부로 돌아갑니다.
전화 번호가 있고 이름을 찾으려면 어떻게합니까? 경찰은 전화 번호부를 역으로 가지고 있지만 일반인에게는 이러한 조회가 거부됩니다. 아니면 그들입니까? 기술적으로 일반 전화 번호부에서 번호 조회를 반대로 할 수 있습니다. 어떻게?
이름에서 시작하여 숫자를 비교하십시오. 일치하는 게임이라면 그렇지 않으면 다음 게임으로 넘어갑니다. 전화 번호부가 순서 가 맞지 않기 때문에 (전화 번호로) 이 방법을 사용해야 합니다.
전화 번호가 주어진 이름을 찾으려면 (역방향 조회) :
- 가장 좋은 경우 : O (1);
- 예상 사례 : O (n) (50 만); 과
- 최악의 경우 : O (n) (100,000).
이것은 컴퓨터 과학에서 매우 유명한 문제이며 언급 할 가치가 있습니다. 이 문제에는 N 개의 도시가 있습니다. 각 도시는 일정 거리의 도로로 1 개 이상의 다른 도시와 연결되어 있습니다. Traveling Salesman 문제는 모든 도시를 방문하는 가장 짧은 여행을 찾는 것입니다.
간단하게 들리나요? 다시 생각 해봐.
모든 쌍 사이에 도로가있는 3 개의 도시 A, B 및 C가있는 경우 다음을 수행 할 수 있습니다.
- A → B → C
- A → C → B
- B → C → A
- B → A → C
- C → A → B
- C → B → A
글쎄, 실제로는 그 중 일부가 동일하기 때문에 그보다 적습니다 (예 : A → B → C 및 C → B → A는 예를 들어 동일한 도로를 반대로 사용하기 때문에 동일합니다).
실제로 3 가지 가능성이 있습니다.
- 이것을 4 개의 도시로 가져 가면 12 개의 가능성이 있습니다.
- 5는 60입니다.
- 6은 360이됩니다.
이것은 factorial 이라는 수학적 연산의 함수입니다 . 원래:
- 5! = 5 × 4 × 3 × 2 × 1 = 120
- 6! = 6 × 5 × 4 × 3 × 2 × 1 = 720
- 7! = 7 × 6 × 5 × 4 × 3 × 2 × 1 = 5040
- …
- 25! = 25 × 24 ×… × 2 × 1 = 15,511,210,043,330,985,984,000,000
- …
- 50! = 50 × 49 ×… × 2 × 1 = 3.04140932 × 10 64
따라서 Traveling Salesman 문제의 Big-O는 O (n!) 또는 계승 또는 조합 복잡성 입니다.
200 개 도시에 도착할 때까지는 기존 컴퓨터의 문제를 해결할 충분한 시간이 우주에 남아 있지 않습니다.
생각할 것.
내가 간단히 언급하고 싶은 또 다른 요점은 O (n a ) 의 복잡성을 갖는 알고리즘 은 다항식 복잡도 를 갖 거나 다항식 시간으로 해결할 수 있다는 것입니다 .
O (n), O (n 2 ) 등은 모두 다항식 시간입니다. 다항식 시간에서는 일부 문제를 해결할 수 없습니다. 이 때문에 세상에는 어떤 것들이 사용됩니다. 공개 키 암호화 가 대표적인 예입니다. 매우 큰 두 가지 주요 요소를 찾는 것은 계산 상 어렵습니다. 그렇지 않은 경우 사용하는 공개 키 시스템을 사용할 수 없었습니다.
어쨌든, 그것은 Big O (개정)에 대한 나의 (희망 평범한 영어) 설명을위한 것입니다.
입력 크기에 따라 알고리즘이 어떻게 확장되는지 보여줍니다.
O (n 2 ) : 2 차 복잡성
항목 수는 10 배 증가하지만 시간은 10 2 배 증가합니다 . 기본적으로 n = 10이므로 O (n 2 ) 는 10 2 인 스케일링 계수 n 2 를 제공합니다 .
O (n) : 선형 복잡도 로 알려진
이번에는 항목 수가 10 배 증가하여 시간도 늘어납니다. n = 10이므로 O (n)의 스케일링 계수는 10입니다.
O (1) : 상수 복잡성
항목 수는 여전히 10 배 증가하지만 O (1)의 배율은 항상 1입니다.
O (log n) : 대수 복잡성
계산 횟수는 입력 값의 로그만큼만 증가합니다. 따라서이 경우 각 계산에 1 초가 걸리면 입력 로그가 n
필요한 시간 log n
입니다.
그것이 요점입니다. 수학을 줄이면 정확히 n 2 이 아니 거나 말한 것이 아닐 수 있지만 스케일링에서 지배적 인 요소가 될 것입니다.
Big-O 표기법 ( "점근선 성장"표기법이라고도 함)은 원점 근처에서 일정한 요인과 물건을 무시할 때 기능 이 어떻게 보이는지 입니다. 우리는 그것을 어떻게 스케일 하는가 에 대해 이야기하기 위해 사용합니다 .
기초
"충분히"큰 입력을 위해 ...
f(x) ∈ O(upperbound)
f
"보다 빠르지 않다"는 의미upperbound
f(x) ∈ Ɵ(justlikethis)
f
"정확히 자란다" 라는 의미justlikethis
f(x) ∈ Ω(lowerbound)
f
"보다 느리게 성장하지 않는다"는 의미lowerbound
big-O 표기법은 상수 요소를 신경 쓰지 않습니다. 함수 9x²
는 "정확하게 성장합니다"라고 10x²
합니다. 둘 다 큰-O하지 않습니다 점근 에 대한 표기주의를 비 점근 함수가 : ( "문제의 크기가 작은 경우 어떻게됩니까" "기원 근처 물건"또는) 물건 10x²
"성장 정확히 같은"을 말한다 10x² - x + 2
.
왜 방정식의 작은 부분을 무시하고 싶습니까? 더 큰 스케일을 고려할 때 방정식의 큰 부분으로 인해 왜소하게 왜곡되기 때문입니다. 그들의 기여는 왜소하고 무관심해진다. (예제 섹션 참조)
다시 말해, 무한대로 갈 때의 비율 에 관한 것 입니다. 실제 시간을로 나누면 O(...)
큰 입력의 한계에 일정한 요소가 생깁니다. 직관적으로 이것은 의미가 있습니다. 함수를 곱하여 다른 함수를 얻을 수 있다면 함수는 서로 "비교"됩니다. 우리가 말할 때입니다 ...
actualAlgorithmTime(N) ∈ O(bound(N))
e.g. "time to mergesort N elements
is O(N log(N))"
... 이것은 "충분히 큰"문제 크기 N (원점 근처의 것을 무시하는 경우)에 대해 다음과 같은 상수 (예 : 2.5, 완전히 구성됨)가 있음을 의미합니다.
actualAlgorithmTime(N) e.g. "mergesort_duration(N) "
────────────────────── < constant ───────────────────── < 2.5
bound(N) N log(N)
많은 상수 선택이 있습니다. 종종 "최상의"선택은 알고리즘의 "일정한 요인"으로 알려져 있지만 가장 큰 용어를 무시하는 것처럼 종종 무시합니다 (일반적으로 중요하지 않은 이유는 상수 요인 섹션 참조). 또한 "며 바운드로 위의 방정식 생각할 수있는 , 걸리는 시간은 약보다 더 없을 것 최악의 경우 N*log(N)
(일정한 요인은 우리가 많이 걱정하지 않는다) 2.5 배 내 " .
일반적으로 O(...)
최악의 행동에 관심을 갖기 때문에 가장 유용합니다. f(x)
프로세서 나 메모리 사용량과 같이 "나쁜"것을 나타내는 경우 " f(x) ∈ O(upperbound)
"는 " upperbound
가 프로세서 / 메모리 사용량의 최악의 시나리오 "를 의미 합니다.
응용
순전히 수학적 구성으로서, big-O 표기법은 처리 시간과 메모리에 관해 이야기하는 것으로 제한되지 않습니다. 이를 사용하여 다음과 같이 스케일링이 의미가있는 모든 경우의 증상에 대해 논의 할 수 있습니다.
N
파티에서 사람들 사이에 가능한 핸드 셰이크 수 ( Ɵ(N²)
특히 N(N-1)/2
, "스케일"과 같은 것이 중요합니다 N²
)예
위의 핸드 셰이크 예에서는 방의 모든 사람이 다른 사람의 손을 흔 듭니다. 이 예에서는 #handshakes ∈ Ɵ(N²)
. 왜?
약간 백업하십시오 : 악수의 수는 정확히 n-choose-2 또는 N*(N-1)/2
(각 N 명의 사람들이 다른 사람들의 N-1 악수를하지만이 두 번의 악수는 2로 나눕니다) :
그러나 매우 많은 수의 사람들의 경우 선형 항 N
은 왜소 해져서 비율에 0을 효과적으로 기여합니다. 따라서 스케일링 동작은 order N²
또는 "N²처럼 커지는 핸드 셰이크 수"입니다.
#handshakes(N)
────────────── ≈ 1/2
N²
마치 차트의 대각선에있는 빈 상자 (N * (N-1) / 2 확인 표시)가없는 것처럼 보입니다 (N 2 확인 표시가 그대로 표시됨).
( "일반 영어"의 일시적인 위반 :) 이것을 스스로 증명하고 싶다면, 여러 대수로 나누기 위해 비율에 대한 간단한 대수를 수행 할 수 있습니다 ( lim
"한도에서 고려 됨"을 의미 함). 그것을 보지 못했다면, 그것은 단지 "N은 정말로 크다"라는 표기입니다.
N²/2 - N/2 (N²)/2 N/2 1/2
lim ────────── = lim ( ────── - ─── ) = lim ─── = 1/2
N→∞ N² N→∞ N² N² N→∞ 1
┕━━━┙
this is 0 in the limit of N→∞:
graph it, or plug in a really large number for N
tl; dr : 큰 값의 경우 핸드 셰이크 수 'x²'가 너무 커서 # handshakes / x² 비율을 기록하면 정확히 x² 핸드 셰이크가 필요하지 않다는 사실 조차 나타나지 않습니다. 임의로 큰 동안 10 진수로.
예 : x = 1 백만, 비율 # handshakes / x² : 0.499999 ...
직관
이를 통해 다음과 같은 진술을 할 수 있습니다.
" 입력 크기를 충분히 크게하려면 상수 크기 가 무엇이든 입력 크기를 두 배로 늘리면 ...
N → (2N) = 2 ( N )
N² → (2N) ² = 4 ( N² )
cN³ → c (2N) ³ = 8 ( cN³ )
c log (N) → c log (2N) = (c log (2)) + ( c log (N) ) = (고정 금액) + ( c log (N) )
c * 1 → c * 1
O (N 1.000001 ) 보다 작습니다. 기본적으로 선형 호출 할 수 있습니다.
2 N → 2 2N = (4 N ) ............ 다른 방법으로 ............ 2 N → 2 N + 1 = 2 N 2 1 = 2 2 N
[수학적으로 기울어 진 경우 작은 스포일러 위로 마우스를 움직일 수 있습니다]
( https://stackoverflow.com/a/487292/711085에 크레딧으로 )
(기술적으로 상수 요소는 좀 더 난해한 예에서 중요 할 수 있지만 위의 내용을 말하지 않았습니다 (예 : log (N)) 그렇지 않습니다)
이들은 프로그래머와 응용 컴퓨터 과학자들이 참조 점으로 사용하는 빵과 버터의 성장 순서입니다. 그들은 항상 이것을 본다. (기술적으로 "입력을 두 배로하면 O (√N) 알고리즘이 1.414 배 느려진다"고 생각할 수 있지만 "로그보다 나쁘지만 선형보다는 낫다"고 생각하는 것이 좋습니다.
일정한 요인
일반적으로 특정 상수 요소가 무엇인지는 중요하지 않습니다. 함수가 성장하는 방식에 영향을 미치지 않기 때문입니다. 예를 들어, 두 알고리즘 모두 O(N)
완료 하는 데 시간이 걸리지 만 하나는 다른 것보다 두 배 느릴 수 있습니다. 최적화가 까다로운 사업이기 때문에 요소가 너무 크지 않으면 우리는 일반적으로 너무 신경 쓰지 않습니다 (최적화는 언제입니까? ); 또한 더 나은 big-O로 알고리즘을 선택하는 단순한 행동은 종종 성능을 몇 배나 향상시킵니다.
무조건적으로 우수한 일부 알고리즘 (예 : 비 비교 O(N log(log(N)))
정렬)은 상수 요소 (예 :)가 너무 크 100000*N log(log(N))
거나 O(N log(log(N)))
숨겨진 것과 같이 상대적으로 큰 오버 헤드를 가질 수 있으므로 + 100*N
"빅 데이터"에서도 사용할 가치가 거의 없습니다.
O (N)이 때로는 최선 인 이유, 즉 데이터 구조가 필요한 이유
O(N)
알고리즘은 모든 데이터를 읽어야하는 경우 "최상의"알고리즘입니다. 읽는 행위 자체 데이터의 무리가 있습니다 O(N)
작업. 메모리에로드하는 것은 일반적으로 O(N)
(또는 하드웨어를 지원하는 경우 더 빠르거나, 이미 데이터를 읽은 경우 전혀 시간이 없음) 그러나 모든 데이터 조각 (또는 다른 모든 데이터 조각) 을 만지거나 살펴보면 알고리즘 O(N)
이이 모양을 수행하는 데 시간 이 걸립니다 . 실제 알고리즘이 얼마나 오래 걸리더라도 적어도 O(N)
모든 데이터를 보는 데 시간 이 걸리기 때문에 시간이 많이 걸립니다.
바로 글쓰기 행위에 대해서도 마찬가지 입니다. N 개를 출력하는 모든 알고리즘은 출력 시간이 적어도 길기 때문에 N 시간이 걸립니다 (예 : N 개의 재생 카드 세트는 모든 순열을 인쇄 (재배 열하는 방법)하는 것이 중요합니다 :) O(N!)
.
이것은 데이터 구조 의 사용에 동기를 부여합니다 . 데이터 구조는 한 번만 (일반적으로 O(N)
시간) 데이터를 읽고, 작게 유지하려는 임의의 양의 전처리 (예 : O(N)
또는 O(N log(N))
또는 O(N²)
)를 요구합니다. 그런 다음 데이터 구조 (삽입 / 삭제 등)를 수정하고 데이터에 대한 쿼리를 작성하는 데 시간이 거의 걸리지 않습니다 (예 : O(1)
또는) O(log(N))
. 그런 다음 많은 수의 쿼리를 진행합니다! 일반적으로 미리 할 일이 많을수록 나중에해야 할 일이 줄어 듭니다.
예를 들어, 수백만 개의 도로 세그먼트의 위도 및 경도 좌표가 있고 모든 거리 교차로를 찾고 싶다고 가정하십시오.
O(N)
작업 방법을 한 번만 수행해야하는 것은 문제가되지 않지만 여러 번 (이 경우에는 N
각 세그먼트에 대해 한 번씩) 수행해야합니다. O(N²)
작업 또는 1000000² = 1000000000000 작업 을 수행해야 합니다. 좋지 않습니다 (현대 컴퓨터는 초당 약 10 억 번의 작업을 수행 할 수 있습니다).O(N)
. 그 후, 키로 무언가를 찾는 데 평균적으로 일정한 시간이 걸립니다 (이 경우 키는 위도 및 경도 좌표이며 그리드로 반올림됩니다. 우리는 9 개만있는 인접한 그리드 공간을 검색합니다. 일정한).O(N²)
관리 가능한 것 까지 진행되었으며, O(N)
우리가해야 할 일은 해시 테이블을 만들기 위해 약간의 비용을 지불하는 것입니다.이야기의 교훈 : 데이터 구조를 통해 작업 속도를 높일 수 있습니다. 더욱이, 고급 데이터 구조를 사용하면 믿을 수 없을 정도로 영리한 방식으로 작업을 결합, 지연 또는 무시할 수 있습니다. 다른 문제는 다른 유추가있을 수 있지만, 우리가 관심을 갖는 일부 구조를 이용하거나 부기 관리를 위해 인위적으로 부과 한 방식으로 데이터를 구성해야합니다. 사전 계획 (기본 계획 및 구성)을 수행하므로 반복 작업이 훨씬 쉬워집니다.
실제 예 : 코딩하는 동안 성장 순서 시각화
점근 적 표기법의 핵심은 프로그래밍과는 별개입니다. 점근 표기법은 다양한 분야에서 사물이 어떻게 확장되고 사용될 수 있는지에 대한 수학적 틀입니다. 그것은 말했다 ... 이것은 코딩에 점근 표기법을 적용 하는 방법 입니다.
기본 사항 : 크기 A의 컬렉션 (예 : 배열, 집합, 맵의 모든 키 등)의 모든 요소와 상호 작용하거나 루프의 반복을 수행 할 때마다 크기 A의 곱셈 요소 루프와 함수 (거의 정의에 따라)에 곱하기 실행 시간이 있기 때문에 반복 횟수, 루프에서 수행 한 작업 시간 (또는 함수 : 호출 횟수) 기능, 시간은 기능에서 수행됩니다). (루프 건너 뛰기 또는 루프를 조기에 종료하거나 인수를 기반으로 함수의 제어 흐름을 변경하는 것과 같이 멋진 작업을 수행하지 않는 경우 유지됩니다. 의사 코드와 함께 시각화 기술의 몇 가지 예가 있습니다.
(여기서 x
s는 상수 시간 작업 단위, 프로세서 명령어, 인터프리터 opcode 등을 나타냅니다)
for(i=0; i<A; i++) // A * ...
some O(1) operation // 1
--> A*1 --> O(A) time
visualization:
|<------ A ------->|
1 2 3 4 5 x x ... x
other languages, multiplying orders of growth:
javascript, O(A) time and space
someListOfSizeA.map((x,i) => [x,i])
python, O(rows*cols) time and space
[[r*c for c in range(cols)] for r in range(rows)]
예 2 :
for every x in listOfSizeA: // A * (...
some O(1) operation // 1
some O(B) operation // B
for every y in listOfSizeC: // C * (...
some O(1) operation // 1))
--> O(A*(1 + B + C))
O(A*(B+C)) (1 is dwarfed)
visualization:
|<------ A ------->|
1 x x x x x x ... x
2 x x x x x x ... x ^
3 x x x x x x ... x |
4 x x x x x x ... x |
5 x x x x x x ... x B <-- A*B
x x x x x x x ... x |
................... |
x x x x x x x ... x v
x x x x x x x ... x ^
x x x x x x x ... x |
x x x x x x x ... x |
x x x x x x x ... x C <-- A*C
x x x x x x x ... x |
................... |
x x x x x x x ... x v
예 3 :
function nSquaredFunction(n) {
total = 0
for i in 1..n: // N *
for j in 1..n: // N *
total += i*k // 1
return total
}
// O(n^2)
function nCubedFunction(a) {
for i in 1..n: // A *
print(nSquaredFunction(a)) // A^2
}
// O(a^3)
약간 복잡한 작업을 수행해도 현재 상황을 시각적으로 상상할 수 있습니다.
for x in range(A):
for y in range(1..x):
simpleOperation(x*y)
x x x x x x x x x x |
x x x x x x x x x |
x x x x x x x x |
x x x x x x x |
x x x x x x |
x x x x x |
x x x x |
x x x |
x x |
x___________________|
여기서 가장 작은 인식 가능한 윤곽선이 중요합니다. 삼각형은 2 차원 모양 (A ^ 2)과 마찬가지로 2 차원 모양 (0.5A ^ 2)입니다. 여기서 두 가지의 일정한 요소는 두 요소 사이의 점근 비율로 유지되지만 모든 요소와 마찬가지로 무시합니다 ... (이 기술에 대한 불행한 뉘앙스가 있지만 여기에 들어 가지 않을 수 있습니다.)
물론 이것이 루프와 함수가 나쁘다는 것을 의미하지는 않습니다. 반대로, 그들은 현대 프로그래밍 언어의 빌딩 블록이며, 우리는 그것들을 좋아합니다. 그러나 데이터와 함께 루프와 함수 및 조건을 짜는 방식 (제어 흐름 등)이 프로그램의 시간과 공간 사용을 모방한다는 것을 알 수 있습니다! 시간과 공간 사용이 문제가된다면, 그것은 우리가 영리함에 의지하고 우리가 고려하지 않은 쉬운 알고리즘이나 데이터 구조를 찾아서 어떻게 든 성장 순서를 줄이는 것입니다. 그럼에도 불구하고, 이러한 시각화 기술 (항상 작동하지는 않지만)은 최악의 실행 시간에서 순진한 추측을 제공 할 수 있습니다.
시각적으로 인식 할 수있는 또 다른 사항은 다음과 같습니다.
<----------------------------- N ----------------------------->
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x
x x x x x x x x
x x x x
x x
x
우리는 이것을 재정렬하고 O (N)을 볼 수 있습니다 :
<----------------------------- N ----------------------------->
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x|x x x x x x x x|x x x x|x x|x
또는 O (N * log (N)) 총 시간 동안 데이터의 log (N) 패스를 수행 할 수 있습니다.
<----------------------------- N ----------------------------->
^ x x x x x x x x x x x x x x x x|x x x x x x x x x x x x x x x x
| x x x x x x x x|x x x x x x x x|x x x x x x x x|x x x x x x x x
lgN x x x x|x x x x|x x x x|x x x x|x x x x|x x x x|x x x x|x x x x
| x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x
v x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x
관련이 없지만 다시 언급 할 가치가 있습니다. 해시 (예 : 사전 / 해시 테이블 조회)를 수행하는 경우 이는 O (1)의 요소입니다. 꽤 빠릅니다.
[myDictionary.has(x) for x in listOfSizeA]
\----- O(1) ------/
--> A*1 --> O(A)
재귀 함수 또는 분할 및 정복 알고리즘과 같이 매우 복잡한 작업을 수행 하는 경우 Master Theorem (보통 작동)을 사용하거나 어리석은 경우 Akra-Bazzi Theorem (거의 항상 작동) 을 사용할 수 있습니다. Wikipedia에서 알고리즘 실행 시간.
그러나 프로그래머는 알고리즘 직관이 제 2의 본성이되기 때문에 이와 같이 생각하지 않습니다. 당신은 무언가 비효율적 인 것을 코딩하기 시작하고 즉시 " 엄청나게 비효율적 인 일을하고 있습니까? " 라고 생각할 것 입니다. 대답이 "예"이고 실제로 중요하다고 생각하면 한 걸음 물러나서 여러 가지 속임수를 사용하여 더 빠르게 실행할 수 있습니다 (대답은 항상 "해시 테이블 사용", "트리 사용"은 거의 없음), 아주 조금 더 복잡한 것).
상각 및 평균 대소 문자 복잡성
"약탈 된"및 / 또는 "평균 사례"라는 개념도 있습니다 (이것은 다릅니다).
평균 사례 : 이것은 함수 자체가 아니라 함수의 예상 값에 big-O 표기법을 사용하는 것입니다. 모든 입력이 동일하게 고려되는 일반적인 경우 평균 사례는 실행 시간의 평균입니다. 예를 들어 quicksort를 사용하면 최악의 경우는 O(N^2)
실제로 입력이 좋지 않은 경우에도 일반적인 경우가 일반적입니다 O(N log(N))
(실제로 나쁜 입력의 수는 매우 적기 때문에 평균적으로 눈에 띄지 않습니다).
Amortized Worst-Case : 일부 데이터 구조는 최악의 경우 복잡도를 가질 수 있지만 이러한 작업을 많이 수행하면 평균적인 작업량이 최악의 경우보다 낫습니다. 예를 들어 일반적으로 일정한 O(1)
시간 이 걸리는 데이터 구조가있을 수 있습니다 . 그러나 때로는 O(N)
부기 또는 가비지 수집 또는 무언가를 수행해야하기 때문에 '딸꾹질'하고 하나의 임의 작업에 시간이 걸립니다 ...하지만 딸꾹질을하면 다시 딸꾹질하지 않을 것이라고 약속합니다. 더 많은 작업. 최악의 비용은 여전히 O(N)
작업 당이지만 많은 실행 에서 상각 된 비용 은 O(N)/N
=O(1)
작업 당. 큰 작업은 충분히 드물기 때문에 가끔씩 많은 작업이 작업의 나머지 부분과 일정한 요소로 혼합되는 것으로 간주 될 수 있습니다. 우리는 그 작업이 무의식적으로 사라지는 충분히 많은 수의 호출을 통해 "완전히 암시되어있다"고 말합니다.
상각 분석에 대한 유추 :
당신은 차를 운전합니다. 때때로, 주유소로가는 데 10 분을 소비 한 다음 탱크에 가스를 채우는 데 1 분을 소비해야합니다. 당신이 당신의 차를 가지고 어디든지 갈 때마다 (주유소까지 운전 10 분을 보내고, 몇 초를 갤런의 일부를 채우는 데)한다면, 이것은 매우 비효율적입니다. 그러나 며칠에 한 번씩 탱크를 채우면 주유소로 운전하는 데 소요 된 11 분이 충분히 많은 횟수의 여행으로 "완성"되어 무시할 수 있고 모든 여행이 5 % 더 길다고 가정 할 수 있습니다.
평균 사례와 상각 된 최악 사례의 비교 :
공격자에 대해 합리적으로 걱정 한다면 할부 상환 및 평균 사례 외에도 걱정할 다른 알고리즘 공격 벡터가 많이 있습니다.)
평균 사례와 할부 상환은 모두 스케일링을 염두에두고 생각하고 디자인하는 데 매우 유용한 도구입니다.
이 하위 주제에 관심이있는 경우 평균 사례와 상각 분석의 차이를 참조하십시오 .
다차원 빅오
대부분의 사람들은 직장에 하나 이상의 변수가 있다는 것을 인식하지 못합니다. 예를 들어, 문자열 검색 알고리즘에서 알고리즘은 시간이 걸릴 수 있습니다 O([length of text] + [length of query])
. 즉,와 같은 두 변수에서 선형입니다 O(N+M)
. 다른보다 순진한 알고리즘은 O([length of text]*[length of query])
또는 일 수 있습니다 O(N*M)
. 여러 변수를 무시하는 것은 알고리즘 분석에서 볼 수있는 가장 일반적인 감독 중 하나이며 알고리즘을 설계 할 때 장애를 일으킬 수 있습니다.
전체 이야기
big-O는 전체 이야기가 아니라는 점을 명심하십시오. 캐시 대신 캐시를 사용하거나 디스크 대신 RAM을 사용하거나 병렬화를 사용하거나 미리 작업을 수행하여 병목 현상을 피함으로써 일부 알고리즘의 속도를 크게 높일 수 있습니다. 이러한 기술은 종종 성장 순서와 무관 합니다 "big-O"표기법이지만 병렬 알고리즘의 big-O 표기법에서 코어 수를 자주 볼 수 있습니다.
또한 프로그램의 숨겨진 제약으로 인해 실제로 점근 적 행동에 신경 쓰지 않을 수도 있습니다. 다음과 같이 제한된 수의 값으로 작업 할 수 있습니다.
O(N log(N))
퀵 정렬 을 사용하고 싶지 않습니다 . 작은 입력에서 잘 수행되는 삽입 정렬을 사용하려고합니다. 이러한 상황은 종종 재귀 정렬, 빠른 푸리에 변환 또는 행렬 곱셈과 같은 문제를 더 작은 하위 문제로 나누는 분할 및 정복 알고리즘에서 발생합니다.실제로, 동일하거나 유사한 점근 적 성능을 갖는 알고리즘 중에서도, 상대적인 장점은 다음과 같은 다른 요인에 의해 실제로 유도 될 수 있습니다 O(N log(N))
. 구현의 용이성과 같은 비 성능 고려 사항; 도서관의 이용 가능 여부 및 도서관의 평판 및 유지 관리 수준
프로그램은 또한 500MHz 컴퓨터와 2GHz 컴퓨터에서 느리게 실행됩니다. 우리는 이것을 실제 자원의 한 부분으로 간주하지 않습니다. 왜냐하면 실제 초 당이 아니라 기계 자원 (예 : 클럭 사이클)에 따른 스케일링을 생각하기 때문입니다. 그러나 에뮬레이션에서 실행 중인지 또는 컴파일러가 코드를 최적화했는지의 여부와 같이 성능에 '비밀'로 영향을 줄 수있는 유사한 것들이 있습니다. 이로 인해 일부 기본 작업이 더 길어 지거나 (상대적으로) 일부 작업의 속도가 빨라지거나 속도가 느려질 수 있습니다 (서로에 비해). 효과는 다른 구현 및 / 또는 환경 사이에서 작거나 클 수 있습니다. 약간의 추가 작업을 피하기 위해 언어 나 기계를 전환합니까? 백 가지 이유 (필요성, 기술, 동료, 프로그래머 생산성,
프로그래밍 언어가 사용되는 선택의 효과와 같은 위의 문제는 상수 요소의 일부로 간주되지 않습니다. 그러나 때로는 (드물기는하지만) 영향을 줄 수 있기 때문에이를 알고 있어야합니다 . 예를 들어, cpython에서 기본 우선 순위 큐 구현은 선택적 으로 삽입 또는 find-min을 선택하는 O(log(N))
것이 아니라 점증 적으로 비 최적입니다 O(1)
. 다른 구현을 사용하십니까? 아마도 C 구현이 더 빠르고 다른 곳에서도 비슷한 문제가있을 수 있기 때문에 아마도 아닙니다. 트레이드 오프가 있습니다. 때때로 그들은 중요하고 때로는 중요하지 않습니다.
( 편집 : "일반 영어"설명은 여기서 끝납니다.)
수학 부록
완전성을 기하기 위해 big-O 표기법의 정확한 정의는 다음과 같습니다. f(x) ∈ O(g(x))
"f는 const * g에 의해 점진적으로 상한입니다": x의 유한 한 값 아래의 모든 것을 무시하면 다음과 같은 상수가 있습니다 |f(x)| ≤ const * |g(x)|
. (다른 기호는 다음과 같습니다. O
≤, Ω
≥를 의미합니다. 소문자 변형이 있습니다 : o
<를 ω
의미하고>를 f(x) ∈ Ɵ(g(x))
의미합니다 .) f(x) ∈ O(g(x))
및 f(x) ∈ Ω(g(x))
(g로 상한 및 하한을 의미 ) : f와 같은 상수가 있습니다. const1*g(x)
와 사이의 "대역"에 항상 있습니다 const2*g(x)
. 그것은 당신이 만들 수있는 가장 강력한 점근 적 진술이며==
. (죄송하지만, 명확성을 기하기 위해 지금까지 절대 값 기호에 대한 언급을 연기하기로 결정했습니다. 특히 컴퓨터 과학 상황에서 음수 값이 나타나는 것을 본 적이 없기 때문입니다.)
사람들은 종종 = O(...)
더 정확한 'comp-sci'표기법을 사용하며 완전히 사용하기에 합법적 인을 사용합니다. "f = O (...)"는 "f is order ... / f는 ...에 의해 xxx-bounded입니다."로 읽히고 "f는 무증상이 ... 인 표현입니다"라고 생각됩니다. 나는 더 엄격한 것을 사용하도록 배웠다 ∈ O(...)
. ∈
"의 요소"를 의미합니다 (여전과 같이 읽음). 이 특정한 경우에, O(N²)
{같은 요소를 포함 2 N²
, 3 N²
, 1/2 N²
, 2 N² + log(N)
, - N² + N^1.9
, ...} 무한히 크지 만 여전히 세트입니다.
O와 Ω는 대칭이 아니고 (n = O (n²)이지만 n²는 O (n)이 아님) Ɵ는 대칭이므로 (이 관계가 모두 전이적이고 반사적이므로) Ɵ, 대칭과 전이 및 반사 따라서 모든 함수 집합을 동등성 클래스 로 분할합니다 . 동등성 클래스는 우리가 동일하다고 생각하는 것들의 집합입니다. 즉, (일반적으로 한계를 고려하여 ... 내가 클래스의 정식 / 독특한 '점근 대표'를 찾을 수 있습니다, 당신이 생각할 수있는 모든 기능을 제공, 말을하는 것입니다 생각 ); 모든 정수를 승산 또는 짝수로 그룹화 할 수있는 것처럼 기본적으로 작은 용어를 무시하여 Ɵ가있는 모든 함수를 x-ish, log (x) ^ 2-ish 등으로 그룹화 할 수 있습니다 (그러나 때로는 붙어있을 수 있습니다) 별도의 클래스 인 더 복잡한 함수).
이 =
표기법이 더 일반적 일 수 있으며 세계적으로 유명한 컴퓨터 과학자들이 논문에 사용하기도합니다. 또한, 캐주얼 한 환경에서 사람들은 O(...)
그들이 언제 의미하는지 말할 것입니다 Ɵ(...)
. 일련의 항목 Ɵ(exactlyThis)
이 O(noGreaterThanThis)
... 의 하위 집합이므로 입력하기가 쉽기 때문에 이것은 기술적으로 사실 입니다. ;-)
편집 : 빠른 참고, 이것은 Big O 표기법 (상한)과 Theta 표기법 (상한 및 하한 모두)과 거의 혼동 됩니다. 내 경험상 이것은 실제로 비 학술적 환경에서의 토론에서 일반적입니다. 혼란에 대한 사과.
한 마디로 : 직업의 규모가 커질수록 완료하는 데 시간이 얼마나 더 걸립니까?
분명히 이것은 "size"를 입력으로 사용하고 "take time"을 출력으로 사용하는 것입니다. 메모리 사용 등에 대해 이야기하려는 경우에도 동일한 아이디어가 적용됩니다.
다음은 건조시키고 싶은 N- 셔츠가있는 예입니다. 우리는 것이다 가정 (즉, 인간의 상호 작용을 무시할)는 건조 위치를 얻기 위해 믿을 수 없을 정도로 빠르다. 물론 현실에서는 그렇지 않습니다.
외부 세척 라인 사용 : 무한히 큰 뒤뜰이 있다고 가정하면 세척은 O (1) 시간에 건조됩니다. 당신이 그것을 많이 가지고 있지만, 그것은 동일한 태양과 신선한 공기를 얻을 것이므로 크기는 건조 시간에 영향을 미치지 않습니다.
회전식 건조기 사용 : 각 적재에 10 개의 셔츠를 넣은 다음 1 시간 후에 완료됩니다. (실제 숫자는 무시하십시오. 관련이 없습니다.) 따라서 50 개의 셔츠 를 건조하는 것은 10 개의 셔츠를 건조하는 데 약 5 배가 걸립니다 .
방송 찬장에 모든 것을 담기 : 모든 것을 하나의 큰 더미에 넣고 일반적인 따뜻함을 유지하면 중간 셔츠가 마르기까지 오랜 시간이 걸립니다. 세부 사항을 추측하고 싶지는 않지만 적어도 O (N ^ 2)라고 생각합니다. 세척 부하를 늘리면 건조 시간이 더 빨라집니다.
"big O"표기법의 중요한 측면 중 하나 는 주어진 크기에 대해 어떤 알고리즘이 더 빠를 지 말하지 않는다는 것입니다. 해시 테이블 (문자열 키, 정수 값)과 쌍의 배열 (문자열, 정수)을 가져옵니다. 문자열을 기반으로 해시 테이블 또는 배열의 요소에서 키를 찾는 것이 더 빠릅니까? (즉, 배열의 경우, "문자열 부분이 주어진 키와 일치하는 첫 번째 요소를 찾으십시오.") 해시 테이블은 일반적으로 상각됩니다 (~ = "평균") O (1) — 일단 설정되면 약 1,000,000 개의 엔트리 테이블에서와 같이 100 개의 엔트리 테이블에서 엔트리를 찾는 동시에. 배열에서 요소를 찾는 것은 (인덱스가 아닌 내용을 기반으로) 선형 적입니다. 즉, O (N) — 평균적으로 항목의 절반을 봐야합니다.
조회 배열보다 해시 테이블이 더 빠릅니까? 반드시 그런 것은 아닙니다. 매우 작은 항목 모음이있는 경우 배열이 더 빠를 수 있습니다.보고있는 문자열의 해시 코드를 계산하는 데 걸리는 시간에 모든 문자열을 확인할 수 있습니다. 그러나 데이터 세트가 커지면 해시 테이블은 결국 배열을 이길 것입니다.
Big O는 입력이 커질 때 함수의 증가 동작 (예 : 프로그램 런타임)의 상한을 설명합니다.
예 :
O (n) : 입력 크기를 두 배로 늘리면 런타임이 두 배가됩니다.
O (n 2 ) : 입력 크기가 런타임 4 배를 두 배로 늘리는 경우
O (log n) : 입력 크기가 두 배가되면 런타임이 1 씩 증가합니다
O (2 n ) : 입력 크기가 1 씩 증가하면 런타임이 두 배가됩니다
입력 크기는 일반적으로 입력을 나타내는 데 필요한 비트 단위의 공간입니다.
Big O 표기법은 입력 집합의 크기에 따라 계산 (알고리즘)을 완료하는 데 걸리는 대략적인 측정 값으로 프로그래머가 가장 일반적으로 사용합니다.
Big O는 입력 수가 증가함에 따라 두 알고리즘이 얼마나 잘 확장되는지 비교하는 데 유용합니다.
보다 정확하게 Big O 표기법 은 함수의 점근 적 행동을 표현하는 데 사용됩니다. 이는 함수가 무한대에 접근함에 따라 어떻게 동작 하는지를 의미합니다.
많은 경우 알고리즘의 "O"는 다음 경우 중 하나에 해당합니다.
Big O는 입력 크기가 무한대로 증가함에 따라 함수의 성장 곡선에 의미있는 방식으로 기여하지 않는 요소를 무시합니다. 즉, 함수에 더하거나 곱한 상수는 단순히 무시됩니다.
Big O는 일반적인 방법으로 "내 코드를 실행하는 데 시간 / 공간이 얼마나 걸립니까?"
당신은 종종 O (n), O (n 2 ), O (nlogn) 등을 볼 수 있습니다. 알고리즘은 어떻게 변경됩니까?
O (n)은 Big O가 n임을 의미하며 이제 "N이란 무엇입니까?" "n"은 원소의 양입니다. 이미징 배열에서 항목을 검색하려고합니다. 각 요소와 "정확한 요소 / 항목입니까?"로 살펴 봐야합니다. 최악의 경우, 항목은 마지막 색인에 있습니다. 즉, 목록에 항목이있는 것보다 많은 시간이 걸렸음을 의미합니다. 따라서 일반적으로 "오, n은 공정한 값입니다!" .
따라서 "n 2 "가 무엇을 의미 하는지 이해할 수 있지만 더 구체적으로 말하면 가장 간단하고 간단한 정렬 알고리즘을 가지고 있다는 생각을 가지고 놀 수 있습니다. bubblesort. 이 알고리즘은 각 항목에 대해 전체 목록을 살펴 봐야합니다.
나의 목록
흐름은 다음과 같습니다.
이것은 목록에 "n"개의 항목이있는 모든 항목을 봐야하기 때문에 O n 2 입니다. 각 항목에 대해 모든 항목을 한 번 더보고 비교를 위해이 항목도 "n"이므로 모든 항목에 대해 n * n = n 2를 의미하는 "n"번을 찾습니다.
나는 이것이 당신이 원하는만큼 간단하기를 바랍니다.
그러나 Big O는 시간과 공간의 방식으로 자신을 표현하는 방법 일뿐입니다.
Big O는 알고리즘의 기본 스케일링 특성을 설명합니다.
Big O가 주어진 알고리즘에 대해 알려주지 않는 많은 정보가 있습니다. 뼈를 자르고 알고리즘의 스케일링 특성, 특히 "입력 크기"에 대한 응답으로 알고리즘의 자원 사용 (시간 또는 메모리 생각) 스케일링 방법에 대한 정보 만 제공합니다.
증기 기관과 로켓의 차이점을 고려하십시오. 프리우스 엔진과 람보르기니 엔진과 같이 같은 종류의 다른 종류 일뿐 아니라 핵심적으로 추진 시스템의 종류가 극적으로 다릅니다. 증기 엔진은 장난감 로켓보다 빠를 수 있지만, 증기 피스톤 엔진은 궤도 발사 차량의 속도를 달성 할 수 없습니다. 이러한 시스템은 주어진 속도 ( "입력 크기")에 도달하기 위해 필요한 연료 ( "자원 사용량")의 관계와 관련하여 다른 스케일링 특성을 갖기 때문입니다.
이것이 왜 그렇게 중요한가? 소프트웨어는 최대 1 조 개의 요인으로 크기가 다를 수있는 문제를 처리하기 때문입니다. 잠시 생각해보십시오. 달로 이동하는 데 필요한 속도와 사람의 보행 속도 사이의 비율은 10,000 : 1 미만이며 소프트웨어가 직면 할 수있는 입력 크기 범위에 비해 절대적으로 작습니다. 소프트웨어가 입력 크기에서 천문학적 범위에 직면 할 수 있기 때문에 알고리즘의 Big O 복잡성에 대한 가능성이 있으며, 기본 확장 특성으로 인해 구현 세부 사항을 능가 할 수 있습니다.
표준 정렬 예를 고려하십시오. 버블 정렬은 O (n 2 )이고 병합 정렬은 O (n log n)입니다. 거품 정렬을 사용하는 응용 프로그램 A와 병합 정렬을 사용하는 응용 프로그램 B의 두 가지 정렬 응용 프로그램이 있고 약 30 요소의 입력 크기의 경우 응용 프로그램 A가 정렬시 응용 프로그램 B보다 1,000 배 빠르다고 가정 해 봅시다. 30 개 이상의 요소를 정렬 할 필요가없는 경우 이러한 입력 크기에서 훨씬 빠르기 때문에 응용 프로그램 A를 선호해야합니다. 그러나 천만 개의 항목을 정렬해야 할 경우 응용 프로그램 B는 실제로이 경우 각 알고리즘의 확장 방식으로 인해 응용 프로그램 A보다 실제로 수천 배 빠릅니다.
다음은 Big-O의 일반적인 품종을 설명 할 때 사용하는 평범한 영어 기사입니다.
모든 경우에, 목록에서 더 높은 알고리즘을 목록에서 더 낮은 알고리즘보다 선호하십시오. 그러나 더 비싼 복잡성 클래스로 이동하는 비용은 크게 다릅니다.
O (1) :
성장이 없습니다. 문제의 크기에 관계없이 같은 시간에 문제를 해결할 수 있습니다. 이것은 브로드 캐스트 범위 내에있는 사람들의 수에 관계없이 주어진 거리에서 브로드 캐스트하는 데 동일한 양의 에너지를 소비하는 브로드 캐스트와 다소 유사합니다.
O (log n ) :
이 복잡성은 조금 더 나쁘다는 점을 제외하면 O (1) 과 같습니다 . 모든 실질적인 목적을 위해 이것을 매우 큰 상수 스케일링으로 간주 할 수 있습니다. 1 천에서 10 억 개의 항목을 처리하는 작업의 차이는 단지 6 배에 불과합니다.
O ( n ) :
문제 해결 비용은 문제의 크기에 비례합니다. 문제의 크기가 두 배가되면 솔루션 비용이 두 배가됩니다. 데이터 입력, 디스크 읽기 또는 네트워크 트래픽과 같은 방식으로 대부분의 문제를 컴퓨터로 스캔해야하므로 이는 일반적으로 저렴한 확장 요소입니다.
O ( N 로그 N ) :
이 복잡성은 O ( n ) 과 매우 유사합니다 . 모든 실질적인 목적을 위해, 둘은 동등합니다. 이러한 수준의 복잡성은 일반적으로 여전히 확장 가능한 것으로 간주됩니다. 가정을 조정하여 일부 O ( n log n ) 알고리즘을 O ( n ) 알고리즘 으로 변환 할 수 있습니다 . 예를 들어, 키 크기를 제한하면 O ( n log n ) 에서 O ( n )으로 정렬이 줄어 듭니다 .
O ( n 2 ) :
사각형으로 자라며, 여기서 n 은 사각형의 변의 길이입니다. 이는 네트워크의 모든 사람이 네트워크의 다른 모든 사람을 알 수있는 "네트워크 효과"와 동일한 성장률입니다. 성장은 비싸다. 대부분의 확장 가능한 솔루션은 상당한 체조를 수행하지 않으면 이러한 수준의 복잡성을 가진 알고리즘을 사용할 수 없습니다. 이것은 일반적으로 다른 모든 다항식 복잡성 -O ( n k ) 에도 적용됩니다 .
O ( 2n ) :
확장되지 않습니다. 사소한 규모의 문제를 해결할 희망은 없습니다. 피해야 할 사항을 알고 전문가가 O ( n k ) 에있는 대략적인 알고리즘을 찾는 데 유용합니다 .
Big O는 알고리즘이 입력의 크기와 관련하여 사용하는 시간 / 공간의 양을 측정 한 것입니다.
알고리즘이 O (n)이면 시간 / 공간이 입력과 동일한 속도로 증가합니다.
알고리즘이 O (n 2 )이면 입력 / 제곱의 속도로 시간 / 공간이 증가합니다.
등등.
Big O에 대한 평범한 영어 설명은 무엇입니까? 가능한 한 공식적인 정의가 적고 간단한 수학.
의 평범한 영어 설명 필요 큰-O 표기 :
프로그래밍 할 때 문제를 해결하려고합니다. 우리가 코딩하는 것을 알고리즘이라고합니다. Big O 표기법을 사용하면 알고리즘의 최악의 성능을 표준화 된 방식으로 비교할 수 있습니다. 하드웨어 사양은 시간이 지남에 따라 다양하며 하드웨어를 개선하면 알고리즘을 실행하는 데 걸리는 시간을 줄일 수 있습니다. 그러나 하드웨어를 교체한다고해서 알고리즘이 여전히 동일하기 때문에 시간이 지남에 따라 알고리즘이 더 좋아 지거나 향상되지는 않습니다. 따라서 다른 알고리즘을 비교하고 더 나은지 아닌지를 결정하기 위해 Big O 표기법을 사용합니다.
의 일반 영어 설명 어떤 큰 O 표기법은 다음과 같습니다
모든 알고리즘이 같은 시간에 실행되는 것은 아니며 입력 항목 수에 따라 다를 수 있으며,이를 n이라고 합니다. 이를 기반으로, 우리는 더 나쁜 사례 분석 또는 n 이 커질 수록 런타임의 상한을 고려합니다 . 많은 Big O 표기법이이를 참조하기 때문에 n 이 무엇인지 알고 있어야 합니다.
소프트웨어 프로그램의 속도를 측정하는 것은 매우 어렵고, 시도 할 때 답변은 매우 복잡하고 예외 및 특수 사례로 채워질 수 있습니다. 두 가지 다른 프로그램을 서로 비교하여 "가장 빠른"프로그램을 찾을 때 모든 예외 및 특수 사례가 혼란스럽고 도움이되지 않기 때문에 이는 큰 문제입니다.
이 모든 도움이되지 않는 복잡성의 결과로 사람들은 가능한 가장 작고 복잡한 (수학적) 표현을 사용하여 소프트웨어 프로그램의 속도를 설명하려고합니다. 이러한 표현은 매우 조잡한 근사치입니다. 약간의 운이 있지만 소프트웨어 조각이 빠르거나 느린 지의 "본질"을 포착합니다.
그것들은 근사치이므로, 표현에 문자 "O"(Big Oh)를 사용하여 독자에게 우리가 과도하게 단순화하고 있음을 신호로 보냅니다. (그리고 그 표현이 어떤 식 으로든 정확하다고 아무도 잘못 생각하지 않도록).
"Oh"를 "순서대로"또는 "대략"을 의미하는 것으로 읽는다면 너무 잘못되지 않을 것입니다. (나는 Big-Oh의 선택이 유머를 시도한 것이라고 생각한다).
이러한 "Big-Oh"표현이 시도하는 유일한 것은 소프트웨어가 처리해야하는 데이터의 양을 증가시키면서 소프트웨어가 얼마나 느려지는지를 설명하는 것입니다. 처리해야 할 데이터 양을 두 배로 늘리면 소프트웨어가 작동하는 데 두 배의 시간이 필요합니까? 열 배나? 실제로는 다음과 같이 걱정할 필요가있는 매우 큰 수의 큰 오 표현이 있습니다.
좋은 점 :
O(1)
Constant : 입력이 아무리 크더라도 프로그램 실행 시간이 동일합니다.O(log n)
대수 : 입력 크기가 크게 증가하더라도 프로그램 런타임은 느리게 증가합니다.나쁜 점 :
O(n)
Linear : 프로그램 런타임이 입력 크기에 비례하여 증가합니다.O(n^k)
다항식 :-입력 크기가 커짐에 따라 다항식 함수로 처리 시간이 더 빨라지고 빨라집니다.... 그리고 못생긴 :
O(k^n)
지수 문제의 크기가 약간 증가해도 프로그램 런타임이 매우 빠르게 증가합니다. 지수 알고리즘을 사용하여 작은 데이터 세트를 처리하는 것이 실용적입니다.O(n!)
계승 프로그램 실행 시간은 가장 작고 사소한 데이터 세트를 제외한 다른 것을 기다릴 수있는 시간보다 길어집니다.O(n log n)
이는 좋은 것으로 간주됩니다.
간단한 대답은 다음과 같습니다.
큰 O는 해당 알고리즘에 대한 최악의 시간 / 공간을 나타냅니다. 알고리즘은 해당 한계보다 더 많은 공간 / 시간을 차지하지 않습니다. 큰 O는 극단적 인 경우 시간 / 공간의 복잡성을 나타냅니다.
좋아, 내 2 센트.
Big-O는 프로그램이 소비하는 자원 의 증가율 로 문제 인스턴스 크기
리소스 : 총 CPU 시간 일 수 있으며 최대 RAM 공간 일 수 있습니다. 기본적으로 CPU 시간을 나타냅니다.
문제가 "계산 찾기"라고 말하면
int Sum(int*arr,int size){
int sum=0;
while(size-->0)
sum+=arr[size];
return sum;
}
problem-instance = {5,10,15} ==> problem-instance-size = 3, 루프 내 반복 = 3
problem-instance = {5,10,15,20,25} ==> problem-instance-size = 5 루프 내 반복 = 5
"n"크기의 입력에 대해 프로그램은 어레이에서 "n"반복 속도로 증가하고 있습니다. 따라서 Big-O는 N (O)으로 표현됩니다.
문제가 "조합 찾기"라고 말하면
void Combination(int*arr,int size)
{ int outer=size,inner=size;
while(outer -->0) {
inner=size;
while(inner -->0)
cout<<arr[outer]<<"-"<<arr[inner]<<endl;
}
}
problem-instance = {5,10,15} ==> problem-instance-size = 3, 총 반복 = 3 * 3 = 9
problem-instance = {5,10,15,20,25} ==> problem-instance-size = 5, 총 반복 횟수 = 5 * 5 = 25
크기 "n"을 입력하면 프로그램이 "n * n"반복 속도로 증가합니다. 따라서 Big-O는 N 2 로 O (n 2 ) 로 표시됩니다.
Big O 표기법은 공간 또는 실행 시간 측면에서 알고리즘의 상한을 설명하는 방법입니다. n은 문제의 요소 수 (즉, 배열의 크기, 트리의 노드 수 등)입니다. n이 커질수록 실행 시간을 설명하는 데 관심이 있습니다.
우리가 어떤 알고리즘이 O (f (n))라고 말할 때, 우리는 그 알고리즘에 의해 실행 시간 (또는 필요한 공간)이 항상 일정한 시간 f (n)보다 낮다는 것을 말하고 있습니다.
이진 검색에 O (logn)의 실행 시간이 있다고 말하는 것은 log (n)에 곱할 수있는 상수 c가 있다는 것입니다.이 상수는 항상 이진 검색의 실행 시간보다 큽니다. 이 경우 항상 일정한 log (n) 비교 요소가 있습니다.
즉, g (n)이 알고리즘의 실행 시간 인 경우 g (n) <= c * f (n) 일 때 n> k 일 때 g (n) = O (f (n))이라고합니다. c와 k는 상수입니다.
" Big O에 대한 평범한 영어 설명은 무엇입니까? 가능한 한 공식적인 정의가 적고 간단한 수학으로 "
이러한 아름답고 간단하고 짧은 질문은 적어도 학생이 과외 수업 중에받을 수있는 것처럼 짧은 답변을받을 자격이있는 것 같습니다.
Big O 표기법은 단지 입력 데이터 양 ** 의 관점에서 알고리즘이 얼마나 많은 시간 * 내에 실행될 수 있는지를 나타 냅니다.
(* 멋진, 단위가없는 시간 감각으로!)
** 사람들이 오늘이나 내일 살든 항상 더 많이 원 하기 때문에 중요한 일입니다.
그렇다면 Big O 표기법이 그렇게 훌륭한 점은 무엇입니까?
실질적으로 말하기, 빅 O 분석은 매우 유용하고 중요한 빅 O는 알고리즘의에 정면 초점을두고 있기 때문에 자신의 복잡성과 완전히 무시하고 단순히 비례 상수와 같은 자바 스크립트 엔진, CPU의 속도, 인터넷 연결, 그리고 아무것도를 모델 T 만큼 재 빠르게 구식이 된 모든 것들 . Big O는 현재 또는 미래에 살고있는 사람들에게 똑같이 중요한 방식으로 만 성과에 중점을 둡니다.
큰 O 표기법은 컴퓨터 프로그래밍 / 엔지니어링, 생각과 꿈을 유지하기 위해 모든 좋은 프로그래머에게 영감을 사실의 가장 중요한 원칙에 직접 스포트라이트를 비추 : 기술의 느린 앞으로 행진 이상 결과를 얻을 수있는 유일한 방법은 것입니다 더 나은 발명 알고리즘 .
알고리즘 예 (자바) :
// given a list of integers L, and an integer K
public boolean simple_search(List<Integer> L, Integer K)
{
// for each integer i in list L
for (Integer i : L)
{
// if i is equal to K
if (i == K)
{
return true;
}
}
return false;
}
알고리즘 설명 :
이 알고리즘은 항목을 목록으로 검색하고 키를 찾고
목록의 각 항목을 반복하여 키인 경우 True를 반환합니다.
키를 찾지 않고 루프가 완료되면 False를 반환하십시오.
Big-O 표기법은 복잡성의 상한을 나타냅니다 (시간, 공간, ..)
시간 복잡성에 대한 Big-O를 찾으려면 다음을 수행하십시오.
최악의 경우에 걸리는 시간 (입력 크기와 관련하여)을 계산하십시오.
최악의 경우 : 키가 목록에 없습니다.
시간 (가장 최악의 경우) = 4n + 1
시간 : O (4n + 1) = O (n) | Big-O에서는 상수가 무시됩니다
O (n) ~ 선형
Best-Case의 복잡성을 나타내는 Big-Omega도 있습니다.
베스트 케이스 : 키가 첫 번째 항목입니다.
시간 (최고의 경우) = 4
시간 : Ω (4) = O (1) ~ 즉시 \ 일정
C
더 나을 것 같아요
빅 오
x가 a (예 : a = + ∞)로 갈 때 f (x) = O ( g (x))는 다음 과 같은 함수 k 가 있음을 의미 합니다.
f (x) = k (x) g (x)
k는 (a = + ∞ 인 경우 모든 x> N, | k (x) | <M 과 같이 숫자 N과 M이 있음을 의미합니다 .)
다시 말해, 일반 영어로 : f (x) = O ( g (x)), x → a는 a 근처에서 f 가 g 와 일부 한정된 함수 의 곱으로 분해됨을 의미합니다 .
작은 오
그건 그렇고, 여기에 작은 o의 정의를 비교하기위한 것입니다.
x가 a로 갈 때 f (x) = o ( g (x))는 다음과 같은 함수 k가 있음을 의미합니다.
f (x) = k (x) g (x)
x가 a에 가면 k (x)는 0이됩니다.
예
x → 0 일 때 sin x = O (x).
x → + ∞ 인 경우 sin x = O (1)
x → 0 일 때 x 2 + x = O (x)
x → + ∞ 일 때 x 2 + x = O (x 2 ),
x → + ∞ 인 경우 ln (x) = o (x) = O (x)입니다.
주의! 등호가 "="인 표기법은 "가짜 평등"을 사용합니다. (엑스)). 마찬가지로 "x → + ∞"일 때 "ln (x) = o (x)"를 쓰는 것이 좋지만 공식 "o (x) = ln (x)"는 의미가 없습니다.
더 많은 예
n → + ∞ 일 때 O (1) = O (n) = O (n 2 ) (반대가 아니라면, 동일성은 "가짜"),
n → + ∞ 인 경우 O (n) + O (n 2 ) = O (n 2 )
n → + ∞ 인 경우 O (O (n 2 )) = O (n 2 )
n → + ∞ 인 경우 O (n 2 ) O (n 3 ) = O (n 5 )
다음은 Wikipedia 기사입니다. https://en.wikipedia.org/wiki/Big_O_notation
Big O 표기법은 임의의 수의 입력 매개 변수가 주어지면 알고리즘이 얼마나 빨리 실행되는지 설명하는 방법으로, "n"이라고합니다. 다른 컴퓨터가 다른 속도로 작동하기 때문에 컴퓨터 과학에 유용하며 4.5Ghz 옥토 코어 프로세서가있는 시스템을 실행하는 동안 알고리즘이 5 초가 걸린다는 말은 많이 알려주지 않습니다. 알고리즘에 관계없이 15 년 된 800Mhz 시스템. 따라서 알고리즘이 시간 측면에서 얼마나 빨리 실행되는지 지정하는 대신 입력 매개 변수 수 또는 "n"으로 실행되는 속도를 말합니다. 이러한 방식으로 알고리즘을 설명함으로써 컴퓨터 자체의 속도를 고려하지 않고도 알고리즘의 속도를 비교할 수 있습니다.
내가 주제에 더 기여하고 있는지 잘 모르겠지만 여전히 공유하고 싶다고 생각했습니다. 이 블로그 게시물 에서 Big O에 대한 매우 유용한 (아주 기본적이지만) 설명과 예를 발견했습니다.
예를 들어, 이것은 거북이 기초와 같은 두개골에 대한 기본 사항을 이해하는 데 도움이되었으므로 올바른 방향으로 향하게하는 것은 꽤 10 분 동안 읽은 것이라고 생각합니다.
큰 O에 대해 알아야 할 모든 것을 알고 싶습니까? 나도 그래.
큰 O에 대해 이야기하기 위해, 나는 단지 한 비트를 가진 단어를 사용할 것입니다. 단어 당 하나의 소리. 작은 단어는 빠릅니다. 당신은이 단어들을 알고 있습니다. 나도 소리를냅니다. 그들은 작다. 우리가 사용할 모든 단어를 알게 될 것입니다!
자, 저와 일에 대해 이야기합시다. 대부분의 경우, 나는 일을 좋아하지 않습니다. 당신은 일을 좋아합니까? 당신이하는 경우 일 수 있지만, 나는 확신하지 않습니다.
나는 일하러 가고 싶지 않습니다. 나는 직장에서 시간을 보내고 싶지 않습니다. 만약 내가 길을 가졌다면, 그냥 놀고, 재미있는 일을하고 싶습니다. 나처럼 느끼나요?
지금은 때때로 일하러 가야합니다. 슬프지만 사실입니다. 따라서 직장에있을 때는 규칙이 있습니다. 일을 줄이려고합니다. 내가 할 수있는 일이 거의없는 것처럼. 그럼 놀러가요!
여기 큰 소식이 있습니다. 큰 O는 제가 일하지 않도록 도와 줄 수 있습니다! 큰 O를 알고 있으면 더 많은 시간을 할 수 있습니다. 그것이 큰 O가 나를 돕는 것입니다.
이제 일이 있습니다. 나는이 목록을 가지고 있습니다 : 하나, 둘, 셋, 넷, 다섯, 여섯. 이 목록에 모든 것을 추가해야합니다.
와우, 나는 일이 싫어. 그러나 오, 나는 이것을해야합니다. 그래서 여기 있습니다.
1 더하기 2는 3입니다 ... 더하기 3은 6입니다 ... 4는 ... 모르겠습니다. 나는 길을 잃었다. 머리 속에서하기가 너무 어렵다. 나는 이런 종류의 일을별로 신경 쓰지 않습니다.
그러니 일하지 말자 당신과 저가 얼마나 힘든지 생각해 봅시다. 6 자리 숫자를 더하려면 얼마나해야합니까?
음 .. 어디 한번 보자. 1과 2를 더한 다음 3에 더한 다음 4에 더해야합니다. 전체적으로 6 개의 추가를 계산합니다. 이 문제를 해결하려면 6 가지를 추가해야합니다.
이 수학이 얼마나 어려운지 알려주기 위해 여기에 큰 O가 있습니다.
Big O의 말 :이 문제를 해결하려면 6 가지를 추가해야합니다. 1에서 6까지 각 항목에 대해 하나의 추가. 6 개의 작은 작업 ... 각 작업은 하나의 추가입니다.
글쎄, 나는 지금 그들을 추가하기 위해 노력하지 않을 것입니다. 그러나 나는 그것이 얼마나 어려울 지 안다. 6이 추가됩니다.
아뇨, 이제 더 많은 일이 있습니다. esh. 누가 이런 종류의 물건을 만드는가?!
이제 그들은 1에서 10까지 추가하도록 요청합니다! 내가 그런 짓을 왜 하겠어? 1-6을 추가하고 싶지 않았습니다. 1에서 10까지 추가하는 것은 ... 음… 훨씬 더 어려울 것입니다!
얼마나 더 힘들까요? 더 많은 일을해야합니까? 더 많거나 적은 단계가 필요합니까?
글쎄, 나는 10 개의 추가 작업을 수행해야한다고 생각한다. 열은 여섯 이상입니다. 나는 1에서 6보다 1에서 10까지 더 많이 추가해야합니다!
지금 추가하고 싶지 않습니다. 나는 단지 그렇게 많은 것을 추가하는 것이 어려울 것이라고 생각하고 싶습니다. 그리고 가능한 빨리 플레이하기를 바랍니다.
1에서 6까지 추가하려면 약간의 작업이 있습니다. 그러나 1에서 10까지 더하면 더 많은 작업이 보입니까?
Big O는 당신의 친구이며 나의 것입니다. Big O는 우리가해야 할 일의 양을 생각하도록 도와 주므로 계획을 세울 수 있습니다. 그리고 우리가 큰 O와 친구라면, 그는 그렇게 어려운 일을 선택하도록 도와 줄 수 있습니다!
이제 우리는 새로운 일을해야합니다. 아뇨 나는이 일을 전혀 좋아하지 않는다.
새로운 작업은 1에서 n까지 모든 것을 추가하는 것입니다.
기다림! N은 무엇입니까? 내가 그리워 했어? n이 무엇인지 말하지 않으면 어떻게 1에서 n까지 추가 할 수 있습니까?
글쎄, 나는 n이 무엇인지 모른다. 나는 들리지 않았다. 당신은? 아니? 오 잘 그래서 우리는 일을 할 수 없습니다. 아휴.
그러나 지금 우리는 그 일을하지 않을 것이지만, 우리가 n을 알고 있다면 그것이 얼마나 어려울 지 추측 할 수 있습니다. 우리는 n 개의 것을 더해야했을까요? 물론이야!
이제 여기 O가 오는데, 그는이 작업이 얼마나 힘든지 알려줄 것입니다. 그는 말합니다. 하나부터 N까지 하나씩 모든 것을 추가하는 것은 O (n)입니다. 이 모든 것을 추가하려면 [n을 더해야한다는 것을 알고 있습니다.] [1] 그건 큰 O입니다! 그는 어떤 유형의 일을하는 것이 얼마나 어려운지를 알려줍니다.
나에게 큰 O는 크고 느리고 보스 같은 사람이라고 생각합니다. 그는 일을 생각하지만하지 않습니다. 그는 "그 일이 빠르다"고 말할 수도 있습니다. 또는 그는 "그 작업은 너무 느리고 힘들다"고 말할 수 있습니다. 그러나 그는 일을하지 않습니다. 그는 그 일을보고 나서 시간이 얼마나 걸릴지 알려줍니다.
나는 큰 O를 위해 많은 관심을 가지고있다. 왜? 나는 일하고 싶지 않다! 아무도 일하는 것을 좋아하지 않습니다. 그래서 우리 모두 큰 O를 좋아합니다! 그는 우리가 얼마나 빨리 일할 수 있는지 알려줍니다. 그는 우리가 얼마나 힘든 일인지 생각하도록 도와줍니다.
아, 더 많은 일. 이제 일을하지 말자. 그러나 단계별로 계획을 세우십시오.
그들은 우리에게 10 장의 카드를주었습니다. 그것들은 모두 섞여 있습니다 : 7, 4, 2, 6… 전혀 똑바로 아닙니다. 그리고 지금 ... 우리의 임무는 그것들을 정렬하는 것입니다.
어. 그것은 많은 일처럼 들립니다!
이 갑판을 어떻게 분류 할 수 있습니까? 난 계획을 가지고있어.
데크를 통해 각 카드 쌍을 한 쌍씩 살펴보고 처음부터 끝까지 살펴 보겠습니다. 한 쌍의 첫 번째 카드가 크고 그 쌍의 다음 카드가 작은 경우 교체합니다. 그렇지 않으면, 나는 다음 쌍으로 간다 등등 .. 그리고 곧, 갑판이 완료됩니다.
덱이 완료되면 묻습니다. 그 패스에서 카드를 교환 했습니까? 그렇다면 맨 위에서 다시 한 번 더해야합니다.
어떤 시점에서 언젠가는 스왑이 없을 것이며 우리의 데크는 완료 될 것입니다. 너무 많은 일!
글쎄, 그 규칙에 따라 카드를 정렬하는 것이 얼마나 많은 일입니까?
10 장의 카드가 있습니다. 그리고 대부분의 경우, 즉 행운이 없다면, 갑판을 통해 매번 최대 10 장의 카드 스왑으로 전체 덱을 10 번까지 통과해야합니다.
빅 오, 도와주세요!
Big O가 들어 와서 말합니다 : n 카드의 덱의 경우, 이런 방식으로 정렬하려면 O (N 제곱) 시간 안에 완료됩니다.
그는 왜 n 제곱이라고 말합니까?
음, n 제곱은 n 곱하기 n입니다. 이제, 나는 그것을 얻는다 : n 카드 확인, 갑판을 통해 n 번까지 될 수있는 것. 그것은 각각 n 단계를 가진 두 개의 루프입니다. 그것은해야 할 일의 제곱입니다. 확실히 많은 일입니다!
이제 큰 O가 O (n 제곱) 작업을 수행한다고 말하면 코에 n 제곱 추가를 의미하지는 않습니다. 경우에 따라 약간 작을 수도 있습니다. 그러나 최악의 경우 데크를 분류하는 작업은 n 제곱 단계에 가깝습니다.
이제 여기에 큰 O가 우리의 친구입니다.
Big O는 이것을 지적합니다. n이 커질수록 우리가 카드를 정렬 할 때 작업은 기존의 추가 기능 작업보다 훨씬 더 엄청납니다. 우리는 이것을 어떻게 알 수 있습니까?
음, n이 실제로 커지면 n 또는 n 제곱에 추가 할 수있는 것을 신경 쓰지 않습니다.
큰 n의 경우 n 제곱은 n보다 큽니다.
Big O는 물건을 정렬하는 것이 물건을 추가하는 것보다 어렵다고 말합니다. 큰 n의 경우 O (n 제곱)이 O (n)보다 큽니다. 즉, n이 실제로 커지면 n 개의 혼합 데크를 정렬하려면 n 개의 혼합 된 것을 추가하는 것보다 시간이 더 많이 걸립니다.
Big O는 우리를 위해 일을 해결하지 않습니다. Big O는 작업이 얼마나 힘든지 알려줍니다.
카드 한 벌이 있습니다. 나는 그들을 분류했다. 당신은 도와주었습니다. 감사.
더 빠른 카드 분류 방법이 있습니까? 큰 O가 우리를 도울 수 있습니까?
더 빠른 방법이 있습니다! 배우는 데 약간의 시간이 걸리지 만 작동합니다 ... 아주 빠르게 작동합니다. 당신도 그것을 시도 할 수 있지만, 각 단계마다 시간을내어 자리를 잃지 마십시오.
갑판을 분류하는이 새로운 방법에서는, 우리가 한참 전에 한 쌍의 카드를 점검하지 않습니다. 이 데크를 정렬하는 새로운 규칙은 다음과 같습니다.
하나 : 나는 우리가 지금 작업하는 덱 부분에서 하나의 카드를 선택합니다. 원한다면 나를 위해 하나를 선택할 수 있습니다. (처음으로“지금 작업하는 데크의 일부”는 전체 데크입니다.)
2 : 선택한 카드에서 덱을 펼칩니다. 이 플레이는 무엇입니까? 어떻게합니까? 글쎄, 나는 시작 카드에서 하나씩 내려 가서, 스플레이 카드보다 더 높은 카드를 찾는다.
셋째 : 엔드 카드에서 위로 올라가 스플레이 카드보다 낮은 카드를 찾습니다.
이 두 카드를 찾으면 카드를 교환하고 교체 할 카드를 더 찾습니다. 즉, 나는 2 단계로 돌아가서 당신이 선택한 카드를 더 플레이합니다.
어느 시점 에서이 루프 (2에서 3까지)가 끝납니다. 이 검색의 양쪽 절반이 스플레이 카드에서 만나면 종료됩니다. 그런 다음, 1 단계에서 선택한 카드로 덱을 플레이했습니다. 이제 시작 근처의 모든 카드가 스플레이 카드보다 낮습니다. 끝 근처의 카드는 스플레이 카드보다 더 높습니다. 멋진 트릭!
네 개 (그리고 이것은 재미있는 부분입니다) : 나는 두 개의 작은 데크를 가지고 있습니다. 하나는 스플레이 카드보다 낮고 하나는 더 높습니다. 이제 각 작은 갑판에서 1 단계로갑니다! 즉, 첫 번째 작은 데크의 1 단계부터 시작하여 작업이 완료되면 다음 작은 데크의 1 단계부터 시작합니다.
데크를 부분으로 나누고 더 작고 더 작은 각 부분을 정렬하며 더 이상 할 일이 없습니다. 이제 모든 규칙에 따라 속도가 느려질 수 있습니다. 그러나 나를 믿어 라. 그것은 결코 느리지 않다. 물건을 분류하는 첫 번째 방법보다 훨씬 적은 작업입니다!
이 종류는 무엇입니까? 퀵 정렬이라고합니다! 그 종류는 CAR Hoare 라는 사람에 의해 만들어졌습니다. 그는 그것을 Quick Sort라고 불렀습니다. 이제 빠른 정렬이 항상 사용됩니다!
빠른 정렬은 작은 데크에서 큰 데크를 분할합니다. 즉, 작은 작업에서 큰 작업을 나눕니다.
흠. 거기에 규칙이있을 수 있습니다. 큰 작업을 작게하려면 해체하십시오.
이 종류는 매우 빠릅니다. 얼마나 빨리? Big O는 우리에게 알려줍니다.이 종류의 경우 O (n log n) 작업이 필요합니다.
첫 번째 정렬보다 다소 빠르지 않습니까? 빅 오, 도와주세요!
첫 번째 정렬은 O (n 제곱)입니다. 그러나 빠른 정렬은 O (n log n)입니다. n log n이 n 제곱보다 작다는 것을 알고 있습니다. 그렇기 때문에 빠른 정렬이 빠르다는 것을 알 수 있습니다.
데크를 정렬해야하는 경우 가장 좋은 방법은 무엇입니까? 글쎄, 원하는 것을 할 수 있지만 빠른 정렬을 선택합니다.
빠른 정렬을 선택하는 이유는 무엇입니까? 물론 일하는 것을 좋아하지 않습니다! 할 수있는대로 빨리 일을하고 싶습니다.
빠른 정렬이 덜 작동하는지 어떻게 알 수 있습니까? O (n log n)이 O (n squared)보다 작다는 것을 알고 있습니다. O는 더 작으므로 퀵 정렬은 덜 작동합니다!
이제 내 친구 Big O를 알았습니다. 그는 우리가 일을 덜하도록 도와줍니다. 큰 O를 알고 있다면 작업을 줄일 수 있습니다!
당신은 나와 함께 모든 것을 배웠습니다! 당신은 너무 똑똑합니다! 정말 고맙습니다!
이제 작업이 끝났습니다. 놀러 가자!
[1] : 한 번에 하나의 모든 것을 속이고 추가하는 방법이 있습니다. 가우스라는 어떤 어린이는 8 살 때 이것을 알아 냈습니다. 나는 그렇게 똑똑 하지 않다. 그래서 그가 어떻게했는지 묻지 마라 .
시간 복잡도를 계산하기 위해 가장 일반적으로 사용하는 시간 복잡도를 이해하는 더 간단한 방법은 Big O 표기법입니다. 이렇게하면 N이 무한대에 가까워 질 때 N과 관련하여 실행 시간을 추정 할 수 있도록 모든 상수 요소가 제거됩니다. 일반적으로 다음과 같이 생각할 수 있습니다.
statement;
일정하다. 문의 실행 시간은 N과 관련하여 변경되지 않습니다.
for ( i = 0; i < N; i++ )
statement;
선형입니다. 루프의 작동 시간은 N에 정비례합니다. N이 두 배가되면 작동 시간도 증가합니다.
for ( i = 0; i < N; i++ )
{
for ( j = 0; j < N; j++ )
statement;
}
이차입니다. 두 루프의 실행 시간은 N의 제곱에 비례합니다. N이 두 배가되면 실행 시간이 N * N 증가합니다.
while ( low <= high )
{
mid = ( low + high ) / 2;
if ( target < list[mid] )
high = mid - 1;
else if ( target > list[mid] )
low = mid + 1;
else break;
}
로그입니다. 알고리즘의 실행 시간은 N을 2로 나눌 수있는 횟수에 비례합니다. 이는 알고리즘이 작업 영역을 각 반복마다 절반으로 나누기 때문입니다.
void quicksort ( int list[], int left, int right )
{
int pivot = partition ( list, left, right );
quicksort ( list, left, pivot - 1 );
quicksort ( list, pivot + 1, right );
}
N * log (N)입니다. 실행 시간은 로그인 N 루프 (반복 또는 재귀)로 구성되므로 알고리즘은 선형 및 로그의 조합입니다.
일반적으로 한 차원의 모든 항목으로 작업을 수행하는 것은 선형이고, 두 차원의 모든 항목으로 작업을 수행하는 것은 2 차적이며 작업 영역을 반으로 나누는 것이 로그입니다. 3 차, 지수 및 제곱근과 같은 다른 Big O 측정 값이 있지만 거의 공통적이지 않습니다. 큰 O 표기법은 측정 단위 인 O ()로 설명됩니다. 퀵 정렬 알고리즘은 O (N * log (N))로 설명됩니다.
참고 :이 중 어느 것도 최선, 평균 및 최악의 경우를 고려하지 않았습니다. 각각 고유 한 Big O 표기법이 있습니다. 또한 이것은 매우 간단한 설명입니다. Big O가 가장 일반적이지만 내가 보여준 것보다 더 복잡합니다. 큰 오메가, 작은 o 및 큰 세타와 같은 다른 표기법도 있습니다. 아마도 알고리즘 분석 과정 밖에서 그것들을 만나지 못할 것입니다.
아마존에서 Harry Potter : Complete 8-Film Collection [Blu-ray]을 주문하고 동시에 온라인으로 동일한 영화 컬렉션을 다운로드한다고 가정 해보십시오. 어떤 방법이 더 빠른지 테스트하려고합니다. 배송은 거의 하루가 걸리며 다운로드는 약 30 분 일찍 완료되었습니다. 큰! 따라서 경쟁이 치열합니다.
반지의 제왕, 트와 일 라잇, 다크 나이트 트릴로지 등과 같은 여러 블루 레이 영화를 주문하고 동시에 모든 영화를 온라인으로 다운로드하면 어떻게됩니까? 이번에는 배송이 완료 되려면 하루가 걸리지 만 온라인 다운로드는 완료하는 데 3 일이 걸립니다. 온라인 쇼핑의 경우 구매 한 항목 수 (입력)는 배달 시간에 영향을 미치지 않습니다. 출력은 일정합니다. 우리는 이것을 O (1) 이라고 부릅니다 .
온라인 다운로드의 경우 다운로드 시간은 동영상 파일 크기 (입력)에 정비례합니다. 우리는 이것을 O (n) 이라고 부릅니다 .
실험에서 우리는 온라인 쇼핑이 온라인 다운로드보다 더 잘 확장된다는 것을 알고 있습니다. 알고리즘 의 확장 성과 효율성 을 분석하는 데 도움이되므로 큰 O 표기법을 이해하는 것이 매우 중요 합니다.
참고 : Big O 표기법은 최악 의 알고리즘 시나리오 를 나타냅니다 . O (1) 과 O (n) 이 위 예제의 최악의 시나리오 라고 가정 해 봅시다 .
크기가 n 인 데이터 세트로 무언가를 수행 해야하는 알고리즘 A 에 대해 이야기한다고 가정 해보십시오 .
그런 다음 O( <some expression X involving n> )
간단한 영어로 의미합니다.
A를 실행할 때 운이 좋지 않으면 X (n) 작업을 완료하는 데 많은 시간이 걸릴 수 있습니다.
발생하는 것처럼 꽤 자주 발생하는 특정 함수 ( X (n) 구현 으로 생각 )가 있습니다. 이들은 공지 쉽게 비교된다 (예 : , , , , , 등 ..)1
Log N
N
N^2
N!
A 및 기타 알고리즘 에 대해 이야기 할 때 이들을 비교함으로써 알고리즘의 순위를 쉽게 지정할 수 있습니다. (최악의 경우) 완료해야하는 .
일반적으로 우리의 목표는 가능한 한 낮은 숫자를 반환 하는 함수 를 갖도록 알고리즘 A 를 찾거나 구성하는 것입니다 X(n)
.
머리에 적절한 무한대 개념이 있다면 매우 간단한 설명이 있습니다.
Big O 표기법은 무한히 큰 문제를 해결하는 비용을 알려줍니다.
그리고 더
일정한 요소는 무시할 수 있습니다
알고리즘을 두 배 빠르게 실행할 수있는 컴퓨터로 업그레이드하면 큰 O 표기법이이를 인식하지 못합니다. 상수 인자 개선이 너무 작아서 큰 O 표기법이 작동하는 규모에서도 눈에 띄지 않습니다. 이것은 큰 O 표기법 디자인의 의도적 인 부분입니다.
그러나 상수 요소보다 "큰"것이 감지 될 수 있습니다.
크기가 대략 "무한"한 계산을 수행하는 데 관심이있을 때 큰 O 표기법은 대략 문제를 해결하는 비용입니다.
위의 내용이 의미가 없으면 머리에 호환 가능한 직관적 인 무한대 개념이 없으므로 위의 내용을 모두 무시해야합니다. 이 아이디어를 엄격하게하거나 이미 직관적으로 유용하지 않은 경우 설명 할 수있는 유일한 방법은 먼저 큰 O 표기법이나 이와 유사한 것을 가르치는 것입니다. (앞으로 큰 O 표기법을 잘 이해했다면 이러한 아이디어를 다시 살펴 보는 것이 좋습니다.)
"Big O"표기법에 대한 일반적인 영어 설명은 무엇입니까?
매우 빠른 참고 사항 :
"Big O"의 O는 "Order"(또는 정확하게 "order of")로 표시
되므로 문자를 비교하기 위해 무언가를 주문하는 데 문자 그대로 사용될 수 있습니다.
"Big O"는 두 가지 작업을 수행합니다.
Notations
.가장 많이 사용되는 표기법이 7 개 있습니다.
1
단계적 으로 작업을 수행한다는 것을 의미합니다.logN
단계 2의 순서 로 작업을 완료 함을 의미합니다.N
단계, 공정, 주문 번호 3 으로 작업 완료O(NlogN)
단계 로 작업을 종료 합니다, 좋지 않습니다, 주문 번호 4N^2
단계 로 작업 완료 , 나쁘다, 주문 번호 52^N
단계 로 작업 완료 , 끔찍합니다, 주문 번호 6N!
단계 로 작업 완료 , 끔찍한, 주문 번호 7당신이 표기법을 얻을 가정 O(N^2)
방법을 취소 만이 아니라도 당신이 좋은이 아니라고 볼, N * N이 작업을 수행하는 단계를 소요 O(NlogN)
의 순위에서.
이해하기 쉽도록 줄 끝에서 주문하십시오. 모든 가능성을 고려하면 7 개 이상의 표기법이 있습니다.
CS에서는 작업을 수행하기위한 일련의 단계를 알고리즘이라고합니다.
용어에서 Big O 표기법은 알고리즘의 성능 또는 복잡성을 설명하는 데 사용됩니다.
또한 Big O는 최악의 경우를 설정하거나 상한 단계를 측정합니다.
최상의 경우 Big-Ω (Big-Omega)을 참조 할 수 있습니다.
Big-Ω (Big-Omega) 표기법 (문서) | 칸 아카데미
요약
"Big O"는 알고리즘의 성능을 설명하고 평가합니다.
"Big O"는 알고리즘을 분류하고 비교 프로세스를 표준화합니다.
그것을 보는 가장 간단한 방법 (일반 영어)
입력 매개 변수의 수가 알고리즘의 실행 시간에 어떤 영향을 미치는지 확인하려고합니다. 응용 프로그램의 실행 시간이 입력 매개 변수의 수에 비례하면 n의 Big O라고합니다.
위의 진술은 좋은 출발이지만 완전히 사실은 아닙니다.
보다 정확한 설명 (수학적)
가정
n = 입력 매개 변수 수
T (n) = 알고리즘의 실행 시간을 n의 함수로 표현하는 실제 함수
c = 상수
f (n) = 알고리즘의 실행 시간을 n의 함수로 표현하는 근사 함수
그런 다음 Big O에 관한 한, 근사 f (n)은 아래 조건이 참인 한 충분히 양호한 것으로 간주됩니다.
lim T(n) ≤ c×f(n)
n→∞
n이 무한대에 가까워짐에 따라 방정식 T는 n의 c 곱하기 f의 n보다 작거나 같습니다.
큰 O 표기법에서 이것은 다음과 같이 쓰여집니다.
T(n)∈O(n)
이것은 T의 n이 n의 큰 O에있을 때 읽 힙니다.
영어로 돌아 가기
위의 수학적 정의에 따르면 알고리즘이 n의 Big O라고하면 n (입력 매개 변수 수) 이상의 함수라는 의미 입니다. 알고리즘이 Big O of n이면 자동으로 n의 Big O 제곱입니다.
n의 Big O는 내 알고리즘이 적어도 이만큼 빠르게 실행됨을 의미합니다. 알고리즘의 Big O 표기법을보고 느리게 말할 수는 없습니다. 당신은 빨리 말할 수 있습니다.
확인 이 UC 버클리에서 큰 O에 대한 비디오 자습서를 위해 밖으로. 실제로는 간단한 개념입니다. Shewchuck 교수 (일명 신 수준 교사)가 그것을 설명한다고 들으면 "아, 그게 다야!"라고 말할 것입니다.
나는 큰 O 표기법에 대해 특히 수학에별로 익숙하지 않은 사람에게 정말 훌륭한 설명을 발견했습니다.
https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/
Big O 표기법은 Computer Science에서 알고리즘의 성능 또는 복잡성을 설명하는 데 사용됩니다. Big O는 특히 최악의 시나리오를 설명하며 필요한 실행 시간 또는 알고리즘에 의해 사용 된 공간 (예 : 메모리 또는 디스크)을 설명하는 데 사용될 수 있습니다.
Programming Pearls이나 다른 Computer Science 책을 읽고 수학에 대한 근거가없는 사람은 O (N log N) 또는 다른 겉보기에는 미묘한 구문을 언급하는 장에 도달했을 때 벽에 부딪쳤을 것입니다. 이 기사가 Big O와 Logarithms의 기초를 이해하는 데 도움이되기를 바랍니다.
프로그래머로서의 첫 번째이고 수학자 인 두 번째 (또는 아마도 세 번째 또는 네 번째)로서 Big O를 완전히 이해하는 가장 좋은 방법은 코드로 몇 가지 예제를 생성하는 것입니다. 아래는 가능한 경우 설명과 예와 함께 몇 가지 일반적인 성장 순서입니다.
O (1)
O (1)은 입력 데이터 세트의 크기에 관계없이 항상 같은 시간 (또는 공간)으로 실행되는 알고리즘을 설명합니다.
bool IsFirstElementNull(IList<string> elements) { return elements[0] == null; }
의 위에)
O (N)은 성능이 입력 데이터 세트의 크기에 비례하여 선형 적으로 증가하는 알고리즘을 설명합니다. 아래 예는 또한 Big O가 최악의 성능 시나리오를 선호하는 방법을 보여줍니다. for 루프를 반복하는 동안 일치하는 문자열을 찾을 수 있으며 함수는 일찍 리턴하지만 Big O 표기법은 항상 알고리즘이 최대 반복 횟수를 수행하는 상한을 가정합니다.
bool ContainsValue(IList<string> elements, string value) { foreach (var element in elements) { if (element == value) return true; } return false; }
O (N 2 )
O (N 2 )는 성능이 입력 데이터 세트 크기의 제곱에 직접 비례하는 알고리즘을 나타냅니다. 이는 데이터 세트에 대해 중첩 된 반복을 포함하는 알고리즘에서 일반적입니다. 더 깊은 중첩 반복은 O (N 3 ), O (N 4 ) 등 을 초래합니다 .
bool ContainsDuplicates(IList<string> elements) { for (var outer = 0; outer < elements.Count; outer++) { for (var inner = 0; inner < elements.Count; inner++) { // Don't compare with self if (outer == inner) continue; if (elements[outer] == elements[inner]) return true; } } return false; }
O ( 2N )
O (2 N )은 입력 데이터 세트에 각 additon마다 성장이 두 배로 증가하는 알고리즘을 나타냅니다. O (2 N ) 함수 의 성장 곡선 은 기하 급수적으로 매우 얕게 시작하여 기상 적으로 상승합니다. O (2 N ) 함수 의 예는 피보나치 수의 재귀 계산입니다.
int Fibonacci(int number) { if (number <= 1) return number; return Fibonacci(number - 2) + Fibonacci(number - 1); }
대수
로그는 설명하기가 약간 까다롭기 때문에 일반적인 예를 사용하겠습니다.
이진 검색은 정렬 된 데이터 세트를 검색하는 데 사용되는 기술입니다. 데이터 세트의 중간 요소 (기본적으로 중앙값)를 선택하여 작동하며 목표 값과 비교합니다. 값이 일치하면 성공을 반환합니다. 목표 값이 프로브 요소의 값보다 높으면 데이터 세트의 상반부를 가져 와서 동일한 작업을 수행합니다. 마찬가지로, 목표 값이 프로브 요소의 값보다 낮 으면 하반부에 대해 작업을 수행합니다. 값을 찾을 때까지 또는 더 이상 데이터 세트를 분할 할 수 없을 때까지 각 반복마다 데이터 세트를 절반으로 줄입니다.
이 유형의 알고리즘은 O (log N)으로 설명됩니다. 이진 검색 예제에 설명 된 데이터 세트의 반복 절반은 데이터 세트의 크기가 증가함에 따라 시작 부분에서 피크가되고 천천히 평평 해지는 성장 곡선을 생성합니다. 예를 들어 10 개의 항목을 포함하는 입력 데이터 세트는 완료하는 데 1 초가 걸리고 100 개의 항목을 포함하는 데 2 초가 걸리고 1000 개의 항목을 포함하는 데이터 세트에는 3 초가 걸립니다. 입력 데이터 세트의 크기를 두 배로 늘리면 알고리즘의 단일 반복 후에 데이터 세트가 절반으로 줄어들어 입력 데이터 세트의 크기가 절반으로 줄어듦에 따라 성장에 거의 영향을 미치지 않습니다. 따라서 큰 데이터 세트를 처리 할 때 이진 검색과 같은 알고리즘이 매우 효율적입니다.
알고리즘 : 문제 해결을위한 절차 / 수식
알고리즘을 어떻게 분석하고 알고리즘을 서로 비교할 수 있습니까?
예 : 당신과 친구는 0에서 N까지의 숫자를 합산하는 함수를 만들도록 요청받습니다. f (x)가 나오고 친구가 g (x)가됩니다. 두 함수 모두 결과는 같지만 알고리즘은 다릅니다. 알고리즘의 효율성을 객관적으로 비교하기 위해 Big-O 표기법을 사용 합니다.
Big-O 표기법 : 입력이 임의로 커짐에 따라 런타임이 입력에 비해 얼마나 빨리 증가하는지 설명 합니다.
3 가지 주요 테이크 아웃 :
공간 복잡성 : 시간 복잡성 외에도 공간 복잡성 (알고리즘이 사용하는 메모리 / 공간의 양)도 중요합니다. 작업 시간을 확인하는 대신 메모리 할당 크기를 확인합니다.