TIL

[TIL] 내일배움캠프_Unity 4주차 복습(람다 , LINQ), is,as 연산자, 5주차 강의 - 정렬

Hwone 2023. 8. 25. 21:36

람다

강의를 다 들었지만 람다는 왜 사용하는가? 언제 사용하는가 ?등 다양한 궁금증이 있어어 튜터님을 찾아가 질문을 몇가지 해보았다 

 

1. C#의 람다는 C++의 인라인함수 처럼 호출 과정을 거치지 않고 바로 그 자리에서 코드가 실행되는 것인가 ?

:그렇다 

 

2. 델리게이트를 사용할 때 말고도 간단한 프로퍼티나 함수를 람다를 사용하면 간결해지는데 그럼 간단한 함수는 그냥 람다를 대부분 사용해도 되는건인가?

:그렇다 하지만 가독성이 떨어져서 지양한다 

 

3. 람다는 필수다 아니라 선택인가? 

: 선택이다 (회사바이회사이지만) 현업에서는 거의 사용하지 않는다

 

4.람다의 일회용, 휘발성에 대해서 감이 잘 안 잡힌다 

: 람다의 일회용이라는 것은 일반 함수 처럼 이곳저곳에서 호출을 해줄 수 없고 람다를 사용한 부분에서만 실행된다는

의미이다.

 

추가로 람다는 델리게이트를 사용하여 변수에 할당하거나, 데이터를 탐색하거나 정렬할 때 많이 사용된다 

 

LINQ

데이터 질의 기능을 사용할 수 있는 기능으로 C#의 배열, 컬렉션등 내가 원하는 데이터만 가져오고 싶은 경우 사용할 수 있는 기술이라고 말할 수 있다 

static void Main()
{
	string[] strArr = { "Apple", "Banana", "Car", "Angular", "Add", "Sum" }; 
    
    var linqResult = form str in strAr //foreach문 이라고 생각하면 됨 
    				 //A로 시작하고, 문자열의 길이가 3보다 큰 값 즉, 값의 조건
    				 where str.StartsWit("A") && str.Length>3
                     select str; // 변수에 저장될 값
 }
 
 //실행결과 Apple Angular

장점

- 컴파일 시간에 타입체크를 해서, 프로그램 실행 전에 문제가 되는 코드를 수정할 수 있다 

- 반복문, 조건문을 사용하는 것 보다 코드가 단순해진다 

 

단점

 -복잡한 질의는 작성할 수 없다 

- 조건이 잘못된 경우 for.foreach와 같은 반복문을 사용하는 것보다 성능이 저하될 수 있다 

(그래서 성능이 중요하다면 다른 접근방식을 사용하는 것이 좋다) 

as 연산자 

객체를 캐스팅 할 때 사용되는 연산자로 캐스팅에 성공하면 캐스트 결과를 리턴하고 실패하면 null 값을 리턴한다

(단, as 연산자는 참조타입간의 캐스팅에만 가능하다. 값타입은 불가)

 

클래스간 타입변환을 명시적으로 하면 되는데 왜 as 연산자가 필요한가 ? 

명시적으로 형변환을 하면 실행을 통해 맞게 캐스팅이 되었는지 알 수 있지만 

as연산자를 사용하면 실행을 하지 않아도 성공유무를 알 수 있다 

 

as 연산자 예제 

class Parent {}

class Children : Parent
{
	public void Method() {}
}

static void Main()
{
	Parent parent = new Parent(); 
	Parentparent2 = new Children(); 

	children = parent as Children; //null
	if(!(children == null))
		children.Method(); 
        
    children = parent2 as Children; //캐스팅 성공
    if(!(children == null)
    	children.Method(); 
}

is 연산자

as연산자 처럼 캐스팅 성공 유무를 확인할 수 있지만 캐스팅을 해주지는 않고 캐스팅이 가능하면 true, 불가능하면 false를 리턴한다. 따라서 단지 캐스팅 성공 유무만 판단할 수 있다 

is 연산자 예제 

...
static void Main()
{
	...
	if(parent is Children)
    {
    	children = (Children)parent; 
        chlidren.Method(); 
    }
    
    if(parent2 is Children)
    {
    	children = (Children)parent; 
        children.Method(); //캐스팅 성공
    }
}

4주차 강의에 개념에 대한 내용이 나오지는 않지만 강의에서 사용하는 것을 보다가 모르는 연산자가 나와서 구글링을 통해 정리해보았다

 

5주차 - 정렬 알고리즘 

퀵정렬은 병합정렬과 같이 O(NlonN)으로 작동하지만 병합정렬보다 더 빠르다 

하지만 퀵정렬은 최악의 경우가 있는데 오름차순이나 내림차순으로 정렬이 이미 되어 있는 상황에서 퀵정렬을 하면

pivot은 중앙에 가는 대신 제일 왼쪽에 위치하게 되어 결국 O(N^2)이 되어 성능저하가 있다 

(그래서 실제 라이브러리에서는 퀵정렬로 되어 있지만 피벗을 랜덤하게 택하거나, 피벗 후보를 3개 정해서 그 3개 중에서 중앙값을 피벗으로 두거나, 최악의 경우에도 O(NlogN)이 보장되는 힙소트로 정렬을 한다 그리고 이러한 정렬을 Introspective Sort라고 한다)

 

그래서 정렬 알고리즘을 구현해야할 때에는 퀵정렬 보다는 병합 정렬이 더 좋다고 알고 있었는데 강의에서 알고리즘 문제를 풀 때 퀵 정렬을 구현해서 풀어보라는 문제가 있어서 튜터님에게 또 질문을 해보았다 

 

답변 : 최악의 경우는 사실 개발자의 역량문제로 일어나기 때문에 이것을 방지하면 퀵 정렬이 더 빠르고 

(회사바이회사지만) 현업에서는 정렬을 구현하게 된다면 보통 퀵정렬을 많이 사용한다 

 

추가로 퀵정렬과 병합정렬을 둘 다 구현할 줄 아는게 좋은가? 

: 그럼 아주 좋다 

  병합정렬(MergeSort)  퀵정렬 (Quick Sort)
시간복잡도 O(NlonN)    평균  O(NlogN) - 병합정렬보다 빠르다
   최악 O(N^2)
Stable Sort 
(우선순위가 같은 원소들끼리의 원래 순서가 유지되는 정렬)
O X

 

그래서 나는 둘 다 구현을 해보고 이해 해야겠다...!