Algorithmic Thinking

Algorithmic Thinking 알고리즘적 사고는 현대 디지털 사회에서 문제 해결의 핵심이 되는 인지적 접근 방식. 이는 단순히 컴퓨터 프로그래밍에만 국한되지 않고, 다양한 분야에서 체계적이고 효율적인 문제 해결을 위한 사고 방식으로 발전해왔다. 정의와 본질 알고리즘적 사고란 문제를 일련의 명확하고 실행 가능한 단계들로 분해하여 해결하는 사고 과정. 이는 다음과 같은 핵심 특성을 가진다: 단계적 분해: 복잡한 문제를 작고 관리 가능한 부분들로 나누는 능력 논리적 순서화: 문제 해결 단계를 효율적이고 논리적인 순서로 배열하는 능력 추상화: 문제의 본질을 파악하고 불필요한 세부사항을 제거하는 능력 패턴 인식: 문제들 사이의 공통점을 찾고 일반화하는 능력 효율성 고려: 자원(시간, 공간 등)을 최적화하는 해결책을 모색하는 능력 알고리즘적 사고의 구성 요소 문제 분해(Decomposition) 복잡한 문제를 더 작고 관리 가능한 부분들로 나누는 과정: ...

December 27, 2024 · 4 min · Me

Branch and Bound vs. Backtracking

Back Tracking vs. Branch and Bound 백트래킹(Backtracking)과 분기한정법(Branch and Bound)은 조합 최적화 문제를 해결하기 위한 두 가지 중요한 알고리즘 설계 패러다임이다. 두 기법 모두 모든 가능한 해결책을 체계적으로 탐색하지만, 그 접근 방식과 최적화 전략에는 중요한 차이가 있다. 백트래킹과 분기한정법은 조합 최적화 문제를 해결하기 위한 강력한 도구이다. 백트래킹은 제약 충족 문제에 더 적합하며, 가능한 모든 해결책이나 첫 번째 유효한 해결책을 찾는 데 중점을 둔다. 반면 분기한정법은 최적화 문제에 더 적합하며, 경계값을 사용하여 최적해를 효율적으로 찾는 데 중점을 둔다. ...

January 10, 2025 · 7 min · Me

브루트 포스 (Brute Force)

브루트 포스 (Brute Force) 브루트 포스는 가장 직관적이고 단순한 문제 해결 기법으로, 가능한 모든 경우의 수를 철저하게 조사하여 문제의 해결책을 찾는 방법이다. “무차별 대입법” 또는 “완전 탐색"이라고도 불리는 이 접근법은 컴퓨터 과학과 알고리즘 설계에서 기본적인 방법론으로 사용된다. 브루트 포스는 가장 직관적이고 단순한 문제 해결 접근법으로, 구현이 쉽고 모든 가능한 해결책을 검사하기 때문에 완전성을 보장한다. 그러나 시간 복잡도가 높아 큰 문제에는 적합하지 않다. 실제 응용에서는 브루트 포스를 단독으로 사용하기보다는 다른 최적화 기법과 함께 사용하거나, 더 효율적인 알고리즘이 없는 경우의 대안으로 활용한다. 또한, 브루트 포스는 문제 해결의 기본 접근법으로서 다른 고급 알고리즘의 기초가 된다. ...

October 13, 2024 · 10 min · Me

Linear Data Structure vs Non-Linear Data Structure

Non-Primitive Linear Data Structure vs. Non-Linear Data Structure 데이터 구조는 크게 Linear Data Structure와 Non-Linear Data Structure로 나눌 수 있다. 측면 Linear Data Structure Non-Linear Data Structure 정의 데이터 요소가 순차적 또는 선형적으로 배열된 구조 데이터 요소가 순차적이거나 선형적으로 배열되지 않은 구조 구조 단일 레벨 구조 다중 레벨 구조 데이터 관계 요소 간 1:1 관계 요소 간 1:N 또는 N:N 관계 순회 단일 실행으로 모든 요소 순회 가능 단일 실행으로 모든 요소 순회 불가능 구현 복잡성 구현이 상대적으로 간단 구현이 상대적으로 복잡 메모리 사용 메모리 사용이 덜 효율적 메모리 사용이 더 효율적 시간 복잡도 입력 크기에 따라 증가 특정 작업에서 더 효율적 데이터 접근 순차적 접근 계층적 또는 네트워크 기반 접근 삽입/삭제 상대적으로 간단 더 복잡하지만 유연함 응용 분야 간단한 데이터 저장 및 처리 복잡한 관계 표현, AI, 이미지 처리 등 예시 배열, 연결 리스트, 스택, 큐 트리, 그래프, 해시 테이블, 힙 공통점: ...

October 12, 2024 · 4 min · Me

Primitive data structure vs Non-Primitive data structure

Primitive Data Structure vs. Non-Primitive Data Structure Primitive Data Structure Primitive data structure는 프로그래밍 언어에 내장된 가장 단순하고 기본적인 데이터 타입이다. 이들은 단일 값을 표현하며, 더 이상 분해할 수 없는 가장 작은 단위의 데이터 구조이다. 주요 특징 단순성: 가장 기본적이고 이해하기 쉬운 데이터 타입이다. 고정 크기: 일반적으로 고정된 메모리 크기를 가진다. 효율성: 메모리 사용과 접근 시간 측면에서 매우 효율적이다. 직접 표현: 컴퓨터 하드웨어에서 직접 지원되는 데이터 타입이다. 값 의미론: 변수에 실제 값이 직접 저장된다. 스택 할당: 주로 스택 메모리에 할당되어 빠른 접근이 가능하다. 주요 primitive data structure들을 비교 분석하여 정리한 표: ...

October 12, 2024 · 6 min · Me

슬라이딩 윈도우 기법 (Sliding Window Technique)

슬라이딩 윈도우 기법 (Sliding Window Technique) 슬라이딩 윈도우 기법은 배열이나 문자열과 같은 선형 데이터 구조에서 특정 범위의 요소들을 효율적으로 처리하기 위한 알고리즘 패러다임. 이 기법은 “창문(window)“처럼 움직이는 부분 배열을 이용하여 시간 복잡도를 획기적으로 개선할 수 있는 강력한 문제 해결 방법이다. 슬라이딩 윈도우 기법은 선형 데이터 구조에서 연속된 요소들을 효율적으로 처리하기 위한 강력한 알고리즘 패러다임으로 이 기법을 이해하고 적용하면 중첩 반복문을 사용하는 시간 복잡도를 O(n²)에서 O(n)으로 줄일 수 있어, 성능 개선에 크게 기여할 수 있다. ...

January 24, 2025 · 9 min · Me

Divide and Conquer vs. Brute Force

Divide and Conquer vs. Brute Force 알고리즘은 프로그래밍의 핵심이며, 문제 해결 방식에 따라 효율성과 성능이 크게 달라진다. 두 알고리즘 모두 장단점이 있으며, 상황에 따라 적절한 선택이 필요하다. 먼저 브루트 포스로 문제를 해결한 다음, 필요에 따라 분할 정복과 같은 더 효율적인 알고리즘으로 발전시키는 것이 좋다. 알고리즘의 선택은 문제의 성격, 데이터의 크기, 요구되는 효율성, 그리고 개발자의 친숙도에 따라 달라질 수 있다. Divide and Conquer(분할 정복) 알고리즘 기본 개념 분할 정복은 복잡한 문제를 더 작고 관리하기 쉬운 하위 문제들로 나누어 해결하는 방법이다. 이 알고리즘은 세 가지 주요 단계로 구성된다: ...

January 24, 2025 · 4 min · Me

비결정성 (Non-determinism)

비결정성 (Non-determinism) 알고리즘이나 시스템에서 동일한 입력에 대해 매번 다른 과정을 거쳐 다른 결과를 도출할 수 있는 특성 특징 다중 선택: 각 단계에서 여러 가능한 다음 단계 중 하나를 임의로 선택할 수 있다. 병렬 처리: 여러 가능한 경로를 동시에 탐색할 수 있는 개념적 모델을 제공한다. 결정성과의 차이: 결정성 알고리즘은 각 단계에서 다음 단계가 유일하게 결정되는 반면, 비결정성 알고리즘은 그렇지 않다. 비결정성 알고리즘 비결정성 알고리즘은 다음과 같은 특징을 가진다. 실행 경로의 다양성: 동일한 입력에 대해 여러 가능한 실행 경로가 존재한다. 비결정도: 각 단계에서 선택 가능한 다음 단계의 최대 개수를 비결정도라고 한다. 계산 능력: 비결정성 알고리즘과 결정성 알고리즘의 계산 능력은 동일하다. 응용 NP 문제: 비결정성 알고리즘으로 다항식 시간 내에 해결 가능한 결정형 문제를 NP 문제라고 한다. 유한 오토마타: 비결정적 유한 오토마타(NFA)는 탐색과 백트래킹 기법을 통해 모든 가능한 선택을 시도한다. 탐색 및 백트래킹 알고리즘: 비결정성은 여러 가지 경우를 순차적으로 계산하며 최적값을 갱신하는 백트래킹 기법의 모델로 사용된다. 장점 간결한 표현: 복잡한 언어나 시스템을 비결정성을 통해 더 간결하게 정의할 수 있다. 논증 간소화: 비결정성을 통해 공식적인 논증을 간단히 할 수 있다. 모델링 유연성: 실제 세계의 불확실성이나 복잡성을 모델링하는 데 유용하다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import random import threading # 결정적인 함수의 예 def deterministic_sum(a, b): return a + b # 항상 같은 입력에 대해 같은 결과 # 비결정적인 함수의 예 def non_deterministic_choice(options): return random.choice(options) # 매번 다른 결과가 나올 수 있음 # 비결정적인 멀티스레딩 예제 shared_counter = 0 lock = threading.Lock() def increment_counter(): global shared_counter current = shared_counter # 의도적으로 경쟁 조건을 만듦 threading.Thread(target=lambda: None).start() shared_counter = current + 1 def run_concurrent_increments(n): threads = [] for _ in range(n): t = threading.Thread(target=increment_counter) threads.append(t) t.start() for t in threads: t.join() return shared_counter 다양한 상황에서 발생할 수 있다: ...

October 13, 2024 · 4 min · Me

비결정성 (Non-determinism)

비결정성 (Non-determinism) 알고리즘이나 시스템에서 동일한 입력에 대해 매번 다른 과정을 거쳐 다른 결과를 도출할 수 있는 특성 특징 다중 선택: 각 단계에서 여러 가능한 다음 단계 중 하나를 임의로 선택할 수 있다. 병렬 처리: 여러 가능한 경로를 동시에 탐색할 수 있는 개념적 모델을 제공한다. 결정성과의 차이: 결정성 알고리즘은 각 단계에서 다음 단계가 유일하게 결정되는 반면, 비결정성 알고리즘은 그렇지 않다. 비결정성 알고리즘 비결정성 알고리즘은 다음과 같은 특징을 가진다. 실행 경로의 다양성: 동일한 입력에 대해 여러 가능한 실행 경로가 존재한다. 비결정도: 각 단계에서 선택 가능한 다음 단계의 최대 개수를 비결정도라고 한다. 계산 능력: 비결정성 알고리즘과 결정성 알고리즘의 계산 능력은 동일하다. 응용 NP 문제: 비결정성 알고리즘으로 다항식 시간 내에 해결 가능한 결정형 문제를 NP 문제라고 한다. 유한 오토마타: 비결정적 유한 오토마타(NFA)는 탐색과 백트래킹 기법을 통해 모든 가능한 선택을 시도한다. 탐색 및 백트래킹 알고리즘: 비결정성은 여러 가지 경우를 순차적으로 계산하며 최적값을 갱신하는 백트래킹 기법의 모델로 사용된다. 장점 간결한 표현: 복잡한 언어나 시스템을 비결정성을 통해 더 간결하게 정의할 수 있다. 논증 간소화: 비결정성을 통해 공식적인 논증을 간단히 할 수 있다. 모델링 유연성: 실제 세계의 불확실성이나 복잡성을 모델링하는 데 유용하다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import random import threading # 결정적인 함수의 예 def deterministic_sum(a, b): return a + b # 항상 같은 입력에 대해 같은 결과 # 비결정적인 함수의 예 def non_deterministic_choice(options): return random.choice(options) # 매번 다른 결과가 나올 수 있음 # 비결정적인 멀티스레딩 예제 shared_counter = 0 lock = threading.Lock() def increment_counter(): global shared_counter current = shared_counter # 의도적으로 경쟁 조건을 만듦 threading.Thread(target=lambda: None).start() shared_counter = current + 1 def run_concurrent_increments(n): threads = [] for _ in range(n): t = threading.Thread(target=increment_counter) threads.append(t) t.start() for t in threads: t.join() return shared_counter 다양한 상황에서 발생할 수 있다: ...

October 13, 2024 · 4 min · Me