학교는 왜 목록보다 배열을 가르치는가? [닫은]


36

학교에서 초기 프로그래밍 수업을위한 대부분의 과제는 배열을 사용해야했습니다. 나는 지금 풀 타임으로 일하고 있으며, 내가 작업 한 프로젝트에 배열을 사용하지 않았습니다. 기존 프로젝트에서도 배열을 사용하는 것을 보지 못했습니다. 제 생각에는 List 가 사용하기 쉽고 표준입니다. 교수는 왜 학생들에게 과제에 배열을 사용하도록 지시합니까? 학생들이 기본을 이해하도록하는 것입니까?

대부분의 대학에서 Java를 가르치므로이 질문은 Java에만 해당됩니다.


7
배열이 더 기본적입니다.
user253751

의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
세계 엔지니어

답변:


120

배열은 색인 및 범위와 같은 개념을 가르치기 때문에 컴퓨터 프로그래밍에서 근본적으로 중요한 두 가지 개념입니다.

목록은 "표준" 이 아닙니다 . 어레이가 완벽하게 맞는 다양한 문제 공간이 있습니다.


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
세계 엔지니어

48

컴퓨터가 작동하는 방식을 가장 정확하게 나타내는 데이터 구조로 시작하고 싶었으므로 Lists와 같은 고급 추상화를 도입하기 전에 기본 사항에 익숙해 져 작업하기가 더 쉬워졌습니다. 그렇지 않으면 특정 구조 또는 알고리즘이 일부 작업에서 느리고 빠른 이유를 이해할 수있는 방법이 없습니다. 컴퓨터 메모리가 실제로 링크 된 목록으로 만들어 졌다면 세계는 매우 다른 곳이 될 것입니다.

거의 같은 이유로, 대학의 첫 프로그래밍 수업은 C에 있었고 나머지 수업은 모두 C ++, Java 및 기타 언어로 진행되었습니다. C가 어떻게 든 더 낫거나 더 쉬운 것은 아닙니다 .C (및 배열)는 당신에게서 아무것도 숨기지 않습니다.


7
목록은 실제 코드에서 작업하기가 쉽지만, 배열은 기본적이고 보편적이므로 (자바) 목록은 아니기 때문에 (완전히) 이해하기 쉽고 이해하는 것이 더 중요합니다. 적어도 저의 의견입니다.
Ixrec

21
데이터를 배열에 저장하고 나중에 액세스하는 할당은 데이터 구조 할당 입니다. 당신은 그것을 깨닫지 못했을 수도 있습니다. 더 나은 엔지니어를 생산하거나 기본 계산 모델을 이해하거나 언어의 표준 라이브러리를 배우는 것이 무엇인지 스스로에게 물어봐야합니다. 일반적인 의견 (그리고 나는 동의한다)은 계산의 기본을 먼저 이해하지 않으면 많은 라이브러리 내용을 이해하지 못한다는 것입니다.
Kent A.

12
LinkedList, ArrayList, OrderedList 등. 먼저 어떤 목록을 배워야합니까? 왜 그들이 왜 존재하는지 이해하지 못한다면 어떻게 당신을 위해 감사 할 것입니까?
Kent A.

10
@KentAnderson +1 학교는 데이터 구조를 낮은 수준에서 이해하는 엔지니어를 생산해야합니다. C에서 기본 구조를 쉽게 구현할 수있는 엔지니어를 만드는 것이 이상적입니다. 다른 프로그램은 단순히 JavaSchool입니다.
Christian Willman

2
"컴퓨터 작동 방식을 가장 정확하게 나타내는 데이터 구조부터 시작하고 싶었습니다."– 목록 구조 또는 개체 구조 메모리가있는 컴퓨터는 어떻습니까? "C가 어떤 식 으로든 더 낫거나 더 쉬운 것은 아닙니다. C (및 배열)가 여러분에게 아무것도 숨기지 않습니다." – 컴퓨터에 AS / 400과 같은 포인터가없는 한 C는 VM에서 기본적으로 실행되며 거의 모든 것을 숨 깁니다 .
Jörg W Mittag

21

위의 답변은 훌륭하지만 다른 것을 염두에두고 있습니다. 자바의 main()방법은 학생들이 수업 첫날에 매우 빨리 기본 배열을 만난다는 것을 의미합니다. 왜?

public static void main(String[] args)

Hello World와 그 이후의 글을 쓰기 위해 가장 먼저 다루어야 할 것입니다. (일부 과정에서는 BlueJ와 같은 교육용 IDE를 사용하는 것을 보았습니다.이를 통해 임의의 방법을 실행하기 위해 포인트 앤 클릭을 할 수는 있지만 따로 ​​설정할 것입니다 ...) 조만간이 키워드들은 조만간 대부분의 교사들이 설명하려고합니다. 실제로, 초보자 수준의 고전적인 시험 문제는 학생들에게 기본적인 Hello World 프로그램에서 각 키워드의 의미를 제시하도록하는 것입니다. 주요 메소드 서명의 일부로 무엇을 찾을 수 있습니까? 배열 (그 이유는 부분적으로 기록입니다. Java 1.0에는 ArrayList가 없었습니다). 배열은 기본 지식 세트의 일부입니다. 목록이 없습니다.

즉, 클래스가 ArrayList를 조금 나중에 코스에 도입하는 것은 드문 일이 아닙니다. 특히 객체와 그 사용이 다루어지면. Java에 대한 AP 컴퓨터 과학 커리큘럼조차도 ArrayList가 포함되어 있습니다 (이것은 익숙하지만 Google은 여전히 ​​그렇게 함을 나타냅니다). ArrayList가 List와 나머지 Collections Framework를 구현한다는 사실은 무시합니다.

마지막으로, 대학 CS 프로그램이 학생들에게 훌륭한 Java 개발자가되는 방법을 가르치기보다는 CS와 프로그래밍 개념을 탐구하는 수단으로 Java를 사용하는 것이 저의 경험입니다. 일부 프로그램은 전문 개발자를 사로 잡는 데 더 초점을 맞추고 다른 프로그램은 이론에 더 집중할 수 있지만 두 경우 모두 대부분의 대학 커리큘럼에서 가르치지 않는 실제 전문 업무에서 Java를 사용하는 방법에 대해 배울 것이 많습니다. 이는 효과적인 Java 와 같은 디자인 패턴 및 기술에서 Spring, Hibernate 또는 JUnit과 같은 프레임 워크 또는 JSP 또는 JDBC와 같은보다 일반적인 것들에 이르기까지 다양합니다. 이러한 철학을 염두에두고, 일반적으로 사용되는 ArrayList에 대해 배열을 강조하는 것이 조금 더 의미가 있습니다.


3
@ 중복 제거기. 배열에 관한 요점과 관련이 없으므로 생략했습니다. 또한 System.out.println ( "Hello World!"); 어느 한 쪽.
Zach Lipton

"실제 세계"에 대한 개념과 효과적인 기술의 경우 +1 적어도 내가 학교에있을 때가 아니라 버전 관리를 가르치고있는 사람은 없었습니다. 그러나 나는 고대인입니다.)
David

스케줄러와 같은 다양한 부분을 구현해야하는 운영 체제 수업을 들었습니다. 그 시점에서 우리는 더 많은 일을 할 수 없었기 때문에 한 번에 하나의 조각에만 집중했습니다 . 그러나 그 모든 작품을 동시에 작동 시키려한다는 생각은 "실제"개발 / "대규모 프로그래밍"의 복잡성에 대한 감사의 시작이었습니다.
David

14

1 학년 프로그래밍 클래스가 배열을 사용하는 한 가지 이유는 레거시입니다. 이것이 바로 동적 목록이 포함 된 표준 라이브러리를 사용하기 전에 교수가 배운 방식입니다. 기본 데이터 유형을 사용하는 것이 더 일반적으로 적용됩니다. 배열은 거의 모든 컴퓨터에 존재합니다. 태양 아래 언어 (그리고 소수의 조립 지침으로 구현 될 수 있음). 프로그래밍을 처음 배웠을 때 연결된 목록을 구현하는 것이 과제 중 하나였습니다.

첫 번째 원칙에서 시작한 다음 "이것은 기본 구조입니다.이 언어 (또는 그 라이브러리)는이 모든 것을 수행하는 높은 수준의 데이터 구조를 제공하지만 x, y 및 z는 제공합니다." "이것은 이러한 높은 수준의 데이터 구조입니다. 이제 여기에 핵심이 있습니다." LinkedList와 ArrayList (또는 HashSet과 TreeSet)의 사용 여부에 대한 추론은 일반적으로 2 년 또는 3 년 알고리즘 과정입니다. 목록과지도는 인터페이스가 같고 결과는 동일하지만 크기에 관계없이 응용 프로그램에서 동작이 크게 다를 수 있습니다. 그리고 일단 Programming 101에서 빠져 나간 후에는 Programming 102가 동일한 언어를 사용할 것이라는 보장은 없습니다. 배열의 개념에서 시작한다면 "

입문 과정에서 "목록"보다 "배열"을 선호하는 또 다른 이유는 배열이 기본적으로 이해하기 쉽기 때문입니다. 20 개의 배열 bytes은 20 바이트를 필요로합니다. ).

"목록"은 완전히 다른 물고기 주전자이며 근본적으로 다른 성능 특성으로 여러 가지 방법 (ArrayList, LinkedList 및 아마도 잊어 버린 몇 가지)으로 구현 될 수 있습니다. 다른 List 클래스의 기능에 대한 이해가 없으면 List foo = new ArrayList()vs 를 사용해야하는 시점에 대한 의미있는 토론을 할 수 없습니다 List foo = new LinkedList(). 학생이 List 구현을 사용하도록 시도하면 누군가 다른 구현 대신 ArrayList를 사용하는 이유를 묻습니다. "ArrayList"에는 "Array"라는 단어가 포함되어 있으며 하나가 뒷받침되므로 "배열"에서 "ArrayList"로의 논리적 인 점프는 아닙니다.

널리 알려진 신념과는 달리, 특히 정적 크기 목록을 처리 할 때 List보다 배열을 사용하는 것이 적합한 상황이 있습니다. 여기 몇 가지가 있습니다 :

  • 조회 및 오버 헤드 메소드 호출을 처리하지 않는 때문에 반복이 약간 빠릅니다 : foo[n]역 참조를 어떤 배후가있는 동안, 산술 포인터 않는 foo.get(n)역 참조가, 메소드 호출을 두 번째 역 참조를 수행하고 어쩌면 포인터 연산을 ArrayList를 사용하는 경우 LinkedList는 잠재적으로 List의 모든 요소를 ​​반복해야합니다.
  • 초기화가 훨씬 깨끗합니다. 다른 StackOverflow 질문int[] foo = new int[]{1, 2, 3, 4, 5} 의 제안과 비교

배열이 배열을 대량으로이기는 또 다른 시나리오는 요소를 사용할 수있는 순서가 최종 위치가 알려진 순서와 일치하지만 최종 순서와 일치하지 않는 경우입니다. 경우 perm이다 int[256]순열을 보관 유지하는, 하나는 쉽게 배열이 반전 할 수 있습니다 int[] inv = new int[256]; for (int i=0; i<256; i++) inv[perm[i]]=i; 난 아무것도 하나는 쓸 수 있다고 생각하지 않습니다 ArrayList<>청소로 할 것이다.
supercat

@supercat 그것은 실제로 동적 배열에 대한 문제가 아니라 특정 구현에 관한 문제입니다. ArrayList특정 크기의 기본 초기화 목록을 생성하는 생성자를 쉽게 제공 할 수 있습니다.
Doval

배열 목록이 메소드 호출 오버 헤드를 처리해야한다는 주장을 백업 할 소스가 있습니까? 이론적으로는 않지만, 실제로 나는 놀라지 것 getset인라인되지 않습니다.
Doval

@Doval : 잘 설계된 언어 / 프레임 워크가 항목을 순서대로 항목을 편리하게 추가 할 수있는 동적 배열 유형을 제공해서는 안되는 이유는 없지만 Java는 그러한 유형을 제공하지 않습니다.
supercat

@Doval :하더라도 getset에 늘어선 같은 일이 될 수 있습니다 myList.set(23,myList.get(23)+1)어디 근처 효율적으로 될 것입니다 myArray[23]+=1. 또한 권투가 필요하지 않은 유형의 경우에도 JITter가 for (i=0; i<1000; i++) myList2.set(i+2000,myList2.get(i+3000));성능이 가까운 System.arrayCopy(myArray1,3000,myArray2,2000,1000); 곳의 다른 제품과 동등한 것이라도 매우 놀랄 것입니다 . 프레임 워크의 동적 배열 유형이 빠른 복사 범위 작업을 제공하지 않아야 할 이유는 없습니다. 그러나 Java는 그렇지 않습니다.
supercat

7

Java를 사용하면 모든 유형의 변수를 배열에 저장할 수 있습니다. 대조적 ArrayList으로 참조 저장 만 허용합니다. 하나는 따라서 유용하게 논의하지 않을 수 있습니다 ArrayList자동 권투는 참조 형식에 프리미티브를 변환하고, 어떻게 첫번째 코팅이없는 방법 자동 개봉기 것이다 때때로 프리미티브에 참조 형식을 변환 :

for (int i=10; i<=10000; i*=10)
{
    ArrayList<Integer> l = new ArrayList<Integer>();
    l.add(i);
    l.add(i);
    l.add(l.get(0));
    System.out.print("i=" + i);
    System.out.print(" #0==i:" + (l.get(0)==i));
    System.out.print(" #1==i:" + (l.get(1)==i));
    System.out.print(" #2==i:" + (l.get(2)==i));
    System.out.print(" #0=#1:" + (l.get(0)==l.get(1)));
    System.out.print(" #1=#2:" + (l.get(1)==l.get(2)));
    System.out.println(" #0=#2:" + (l.get(0)==l.get(2)));
}

코드가을 (를) 사용하지 int[3]않고 사용했다면 ArrayList놀라운 일이 없습니다. 세 요소 모두 i가 서로 같고 비교 될 것 입니다. ArrayList그러나을 사용 하면 목록의 세 가지 요소가 모두 항상 같은 것으로 비교 i되고 첫 번째와 세 번째는 항상 서로 같은 것으로 비교되지만 첫 번째 두 요소 i는 1, 10 또는 100 일 때만 서로 동일합니다. (대부분의 구현에서) i1000 또는 10000이 아닌 경우 .


# 0과 # 1이 1 또는 10 또는 100 일 때 왜 같은지 설명 할 수 있습니까? 나는 그 시점까지 추적했다.
Matthew 읽기

2
@MatthewRead :이 Integer클래스에는 중첩 된 클래스가 IntegerCache있는데, 이 클래스는 Integer일반적으로 -128..127로 확장되는 값 범위에 대해 사전 초기화 된 객체를 보유 합니다. 해당 범위 밖의 값을 복싱하려면 새 객체를 만들어야하지만 캐시 된 범위 내의 값을 복싱하면에 저장된 사전 초기화 된 객체 중 하나에 대한 참조가 반환됩니다 IntegerCache.cache. 좋은 자바 프로그래머라면 누구나 Integer같은 값을 캡슐화 하는 두 가지 유형의 변수가 같거나 비교되지 않을 수도 있지만, 그 아이디어를 너무 일찍 도입하면 학생들이 공포에 빠질 수 있습니다.
supercat

허, 그것은 그것이 사전에 초기화 된 물체 때문이라고 생각하지 않았을 것입니다. 정보에 대해서 감사드립니다!
Matthew 읽기

1
@ MatthewRead : Java가와 같은 특정 종류의 암시 적 변환을 허용하지 않기를 바랍니다 ==. 자동 Unboxing이 발생할 가능성을 감안할 때 나는 그것을 완전히 허용하지 않으려는 경향이 있지만 그 행동 ==은 특히 ​​끔찍합니다. ==운영자도 같은 경우에 심하게 동작 16777217==16777216f[사실 보고서]를위한 암시 적 변환은 long v=Math.Round(123456789), w=Math.Round(123456789012345)예상치 못한 쉽다 [당신이 그 표현은 보장 할 것을 추측 할 수?]
supercat

에 관해서는 IntegerCache성능에 도움이 될 수있는 시간이 있지만, 종종 다소 평범한 코드 인 코드가 종종 약간의 작업에 영향을 줄 수 있습니다. 어떤 방법으로, 권투가 두 개의 정수 캐시에서 객체를 준 무작위로 반환하고 캐시 항목을 새로운 것으로 대체하여 무작위로 대체하는 모드가 있기를 바랍니다. 따라서 -128..127 값의 권투 동작에 의존하는 코드는 오랫동안 성공하지 못할 것입니다.
supercat

6

ArrayList배열을 내부적으로 사용 한다는 사실 때문에 배열을 먼저 사용하는 방법을 가르치는 것이 합리적이라고 생각합니다 . 이 ArrayList클래스에는 배열 이라는 멤버 변수 elementDataObject있습니다.

JDK ArrayList 소스 코드에서 :

/**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer.
 */
private transient Object[] elementData;

요소를 추가, 업데이트, 검색 또는 제거 할 ArrayList때이 내부 배열을 사용하여 해당 작업을 수행합니다. 사용자 Ixrec 가 이미 지적했듯이- ArrayList일반적으로 작업하기가 더 쉬운 상위 레벨 추상화입니다.


그러나 배열은 내부적으로 메모리 블록에 대한 포인터를 사용합니다. 특정 추상화 수준에서 시작하는 이유는 무엇입니까?

질문은 태그로 표시 Java됩니다. 일반적으로 사용할 때 왜 배열을 가르치는 지 묻습니다 ArrayList. Java에는 포인터가 없습니다. 옳고 그름은 C / C ++가 Java보다 학생들을 시작하기에 더 좋은 언어라는 의견을 가지고 있습니다. C / C ++에 대한 지식이 있으면 프로그래밍의 많은 주제를 더 잘 이해할 수 있습니다.
Derek W

3

이 목록이 실제로 작업하기가 더 쉽다고 가정하면 실제로 중요하지 않습니다. 학습은 "쉬운 것이 어렵다"보다 "기본에서 복잡한"에 관한 것입니다. 기초가 중요하지 않은 경우 컴퓨터 과학은 학문 분야가 아닙니다. 온라인 자습서의 기존 프레임 워크 / 라이브러리를 사용하여 앱을 함께 클릭하는 방법을 배울 수 있습니다. (물론 누군가는 그 라이브러리를 작성해야하고 누군가는 ArrayList처음 에 구현해야 합니다 ....)


많은 경우에 ArrayList배열을 사용하여 집계하지 않고 함께 계산하고 함께 계산하는 편리한 방법이 없다는 점을 제외하고는 별도의 배열과 "liveItems"수를 사용하여 사용을보다 잘 처리 할 수 ​​있습니다.
supercat

2

학업 교육에서 가장 중요한 것은 자신이하는 일을 설명하기 위해 올바른 용어를 사용하도록 가르치는 것입니다.

리스트는 다른 배열입니다. java.util.List인터페이스이기 때문에 Java 에서는 사용할 수 없습니다 . 일반적으로 java.util.ArrayListList 구현 인 목록을 사용 하고 목록은 아니지만 동적 배열 주위의 객체 래퍼를 사용합니다. 그래서 당신은 'List'를 사용한다고 말하지만 배열을 사용합니다.

용어 혼돈을 건너 뛰고 단순히 배열을 사용하여 학생들에게 배열이 무엇인지 배우는 것이 매우 합리적입니다. Java에서 배열을 사용하는 경우 최소한 배열을 사용하십시오.

솔직히, Java로 프로그래밍을 가르치는 것이 좋은 생각이 아닌 이유이기도합니다. 프로그래밍의 기본 개념을 올바르게 배우기는 어렵습니다.


해시 맵은 어떻습니까? 배열은 일종의 해시 맵입니다.
Thufir

@ Thufir 배열은 어떻게 해시 맵이 될 수 있습니까? 그것들은 완전히 다른 데이터 구조입니다.
Danubian Sailor

해시 맵으로 배열을 나타낼 수 있습니다. 어느 것이 더 "기본"입니까? 해시 맵이 더 개념적으로 흥미 롭다고 주장합니다.
Thufir

1
@Thufir 아니오, 당신은 할 수 없습니다. 에뮬레이션 만 할 수 있습니다. 내부적으로 각 데이터 구조가 그대로입니다. 그것들은 기본적으로 개념적으로 다릅니다. 그렇기 때문에 Java 또는 JavaScript와 같은 매우 추상적 인 언어로 프로그래밍을 배우는 것이 나쁜 생각입니다. 데이터 구조가 실제로 무엇인지 명확하지 않습니다.
Danubian Sailor

1

문자 그대로 배열을 보거나 사용한 적이 없습니까? 우리는 목록 외에도 항상 사용합니다 . 우리는 일반적으로 Java를 사용하지 않지만 명백한 유사성을 이끌어내는 다른 언어를 많이 사용합니다.

배열과 목록 사이에서 하나는 더 가볍고 추가로 더 많은 반면 다른 하나는 더 많은 기능을 제공합니다. 프로그래밍의 일반적인 규칙으로, 기본적으로 해당 라인을 따라 두 개의 유사한 유형이있을 때 실제로 더 멋진 유형이 필요하지 않으면 더 가벼운 유형을 선택해야합니다. 오버 헤드를 줄이는 것 외에도 실제로 프로그램 및 특히 코드 의 혼란과 상태를 처리하는 데 도움이됩니다 . 테스트하는 동안 문제가 발생하면 볼 곳이 적습니다. 더 중요한 것은 배열 대 목록의 경우 실제로 사람들이 실제로 사용하고 수행하려는 작업의 제한된 범위에 대한 더 나은 아이디어를 얻는 것입니다.

그렇습니다. 학문적 관점에서 학생들에게 기본을 가르치는 또 다른 이유가 있습니다. 그러나 이것은 조금 더 깊어집니다. 배열과 목록은 더 가벼운 유형의 기본 인스턴스 위에 만들어지고 종종 감싸는 벌크 유형의 좋은 예입니다. Lists에 기본 배열이없는 경우에도 목록처럼 바깥쪽으로 동작합니다. 누군가에게 List가 무엇인지 가르치는 것의 한 부분은 배열이 무엇인지 가르치는 것입니다.

C ++과 같은 언어에서 이것이 어려울 수 있음을 알 수 있습니다. 여기서 배열은 기본적으로 배열보다 더 많이 제거 할 수 없지만 고급 언어에서는 거의 자체 목록입니다. 주어진 상황에서 귀하의 요구에 완벽하게 부합한다면 왜 다른 것을 사용해야합니까?


목록에 "다른"기능이있는 것처럼 "추가"기능이 있다고는 말할 수 없습니다. 새로운는 T[]는 동안, 임의의 순서로 항목을 적용, 바로 게이트에서, 준비가 될 것입니다 ArrayList<T>이 수정하기 전에 항목을 순서대로 추가해야합니다. A T[]는 임의의 항목 범위를 비슷한 크기의 다른 범위로 T[]비교적 빠르게 복사 할 수 있지만 ArrayList<T>한 목록에서 개별적으로 항목을 읽고 다른 목록에 저장해야합니다 (훨씬 느리고 덜 편리함).
supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.