0. 문제정의 - 전화번호부 만들기※ 전화번호부 만들기- linked list를 사용해서 전화번호부를 만든다.- 동적 할당을 사용해야 한다.- 입력, 추가, 삭제, 수정, 복사하여 새로운 전화번호부 만들기, 두 개의 전화번호부합치기의 기능이 수행되어야 한다.- 기본적인 기능은 주어진다. 함수의 내부를 구현해야 한다.- 수정과 삭제의 경우 이름으로 못 찾으면 false를 반환한다.- find 함수의 경우 못 찾으면 -1을 반환한다.1. 문제해결※ 전화번호부 만들기※ copy constructor● 같은 클래스의 객체에 대한 상수 참조를 인자로 취하는 생성자로 한 값에 대한 사본을 만들기 위해서 사용한다. 어떤 객체의 처음부터 끝까지를 똑같이 같은 객체를 만들 때 사용한다.● 이 프로그램에서는 대입연산자(“=”) 오버로딩을 통해서 복사 생성자를 구현하도록 한다.● 복사 생성자는 전화번호부를 복사하는 과정에서 사용된다. 각각의 처음부터 바꾸어서 넣으려면 귀찮은 작업을 해야 하므로 원래 있던 데이터를 삭제시킨 후에 새로 인자로 받은 데이터를 반복문을 통해서 end 값이 아닐 때까지 새로 넣는다.※ list에서 merge● merge의 사전적인 의미는 합병하다, 합체시키다라는 의미이다. 프로그램 상에서는 두 개 이상의 데이터를 합치는 작업을 의미한다. list에서 merge는 merge sort에서처럼 어려운 알고리즘이 아니다. 물론 그렇게 양쪽에서 하나씩 가지고 와서 할 수도 있지만 정렬되어있지 않은 알고리즘이기 때문에 그러한 알고리즘이 필요가 없다. 단순히 하나의 데이터 내용을 먼저 copy한 다음 나머지 한 개의 데이터 내용을 뒤에 계속 붙이면 된다. 이 과정에서 복사 생성자가 사용된다.● linked list로 구현 시에 처음에 복사하는 데이터는 복사 생성자를 이용해서 복사하고, 그리고 다른 하나는 복사해서 값을 넣는 것이 아니라 원본 데이터에 주소로 연결 될 수 있다는 점을 기억하고 주의해야한다.※ operator overloading● 연산자 오버로딩이란 기존에 정의되어 있는 연산자(+, -, /, * 등등)를 사용자의 편의에 따라 다른 기능으로 재 정의하는 것을 의미한다.● 이 프로그램에서는 전화번호부의 “=”를 사용하여 복사 생성자를 만드는 것과 저번에 했던 부분에서 나왔던 “++”,“==”,“--”,“!=” 등이 여기에 속한다.● 이 프로그램에서는 클래스 내부에서 사용하는 변수로 만들었다.※ destructor● 동적 할당으로 선언된 것의 경우 메모리의 힙 영역에 저장된다. 보통의 메모리의 경우 스택영역에 저장되어서 {}로 끝나게 되면 자동으로 삭제된다. 하지만 힙 영역은 운영체제가 관리하는 영역으로 프로그래머가 new로 선언했을 때 사용할 수 있는 공간으로 C에서는 선언한 프로그래머가 책임지고 메모리를 반환해 주어야 한다. 그렇지 않으면 memory leak이 생겨서 해당 메모리를 사용할 수 없는 공간이 되므로 주의해야한다. 메모리를 반환하기 위해서 사용하는 것이 이 소멸자(destructor)이다. 소멸자는 delete로 선언된 동적 메모리를 삭제하는데 객체의 호출이 끝나게 되면 자동적으로 호출되어 자동으로 반환된다. 하지만 지정하지 않은 경우 메모리에서 계속 사용하게 된다. 또 주의해야 할 점은 배열로 선언된 동적 할당과 하나씩 선언된 동적 할당의 소멸방법이 다르다는 것이다. 배열로 선언된 메모리 영역의 경우 delete [] 객체명; 으로 삭제하고 하나로 선언된 메모리 영역의 경우 delete 객체명;으로 삭제한다.● 이 프로그램에서 소멸자는 전화번호부를 없애는 것으로 사용한다.※ 입력● 입력의 전제조건이 같은 이름이 들어오지 않는 것이다. 물론 그렇지는 않지만 이번 과제에서의 전제조건이었다. 또한 데이터가 정렬되어 있지 않으므로 그냥 맨 뒤에 삽입하도록 한다. list에 있는 멤버 중 push_back을 사용한다.※ 수정● 먼저 이름으로 검색해서 해당 이터레이터를 받는다. 그 후 이터레이터가 가르키는 값을 삭제하고 다시 push_back을 하여 데이터를 넣는다. 여기서도 순서가 상관이 있지 않으므로 이렇게 하는 것이다. 만약 검색한 이름이 없다면 false를 반환한다.※ 수정● 먼저 이름으로 검색해서 해당 이터레이터를 받는다. 그 후 이터레이터가 가르키는 값을 삭제한다. 만약 검색한 이름이 없다면 false를 반환한다.※ 리스트와 다른 구현의 설명은 생략한다.2. 결론이번 과제 같은 경우는 교수님께서 대부분 작성해 놓으신 프로그램을 가지고 일부를 수정해서 만들었기 때문에 평소보다는 쉽게 프로그램을 작성할 수 있었다. 평소에 software reuse를 누누이 말씀하신 교수님의 말씀일 쉽게 이해할 수 있었다. 그리고 항상 많이 보고 많이 작성해 봐야 한다고 말씀하신 것도 이해가 간다. 글을 잘 쓰기 위해서는 책을 많이 봐야 문장력이 느는 것과 같은 이치라고 생각된다. 하지만 다른 사람이 작성한 소스를 보는 것이 쉬운 일은 아니다. 장기나 바둑 같은 경우는 직접 하는 사람보다 옆에서 훈수 두는 사람이 더 잘 하는 것처럼 프로그램도 그런 것이라고 생각해야지. 내 스타일로 작성된 소스가 아니기 때문에 조금 더 주의 깊게 봐야 한다. 그리고 주석이 없으면 이해하지 못하는 부분도 있다. 나를 위해 프로그램을 잘 작성해야 하는 것이 아니라 다른 사람을 위해서 프로그램을 잘 작성해야겠다는 생각을 했다.이 과제에서 어려웠던 부분은 전화번호부의 각 기능을 정확하게 이해하지 못했던 부분이었다. 그래서 어느 함수에서 무엇을 해야 하고, 어느 함수에서 무엇을 인자로 넘겨야하고를 생각하는 과정이 생각보다 오래 걸렸다. 물론 교수님께서 다 정의해 주셨는데도 그랬으니... 모든 것을 프로그램화 하는 연습을 해야겠다.또한 동적배열을 사용할 때 포인터 변수로 사용해야 하는 점이 어려웠다. 포인터의 멤버변수를 사용할 때에는 ->를 사용해야 하는데 익숙하지 않아서 인지 자꾸만 점(.)을 사용하게 된다. 포인터라는 보이지 않는 개념을 생각하려고 하니까 머릿속에 잘 들어오지 않아서 인 것 같다. c에서는 포인터만 이해해도 반 이상 한 것이라고 하는데 그래도 포인터를 알고 있으니까 반이나 알고 있는 것이다! 그 어렵다는 C를 반이나 알고 있다니~ 이제 조금만 더 하면 된다.copy constructor가 잘 이해가 안 되었는데 이 과제를 하면서 조금이나마 감을 잡아서 다행이다. 이번 과제에서는 “=”을 연산자 오버로딩해서 copy constructor를 만들었다. 바로 이 과정에서 “=”이 수행하는 역할이 기존에 있는 전화번호부를 복사해서 새로 만드는 것이기 때문에 copy constructor가 되는 것이다. 만약에 복사 생성자를 다른 함수나 기호로 만들었다면 그것이 복사 생성자가 되겠지만 이 프로그램에서는 흔히 쓰이는 대입연산자의 내용이 복사해서 사용하기 때문에 복사 생성자와 대입연산자가 동일하다.main부분은 구지 손대지 않아도 되는 부분인데 독특하게 해보려고 손댔다가 괜히 일만 커져서 아쉽다. 그래서 결국 다시 원상복구 시켰다. 어떻게 하면 좀 더 편리하게 프로그램을 할 수 있을까? 그리고 좀 더 사람들이 편하게 사용할 수 있을까? 매번 프로세스를 작성하면서 느끼는 부분이다."this"라는 예약어를 사용하는 것이 신기하기만 하다. 나 자신을 반환하고, 나 자신을 인자로 넘기고... 이런 내부적인 기능이 잘 이해는 가지 않는다. 하지만 이 과정에서 “this”라는 것이 많은 일을 하고 있고, 아주 유용하게 쓰인다는 것을 알았다. 이번에는 이 정도 안 것으로 만족한다. 다음에 사용할 때에는 더 깊이 알아봐야겠다.나는 너무 프로그램을 어렵게만 생각하는 것 같다. 사실 그렇게 어려운 개념이 아닌데 작성을 매우 어렵게 하는 것 같아서 아직 갈 길이 멀다고 느낀다. 틀에 박힌 사고와 무엇인가 정확하게 정해져 나오는 것을 좋아하는 나에게 쉽게 생각하고, 바꾸어 생각하는 것이 필요하다고 느껴진다. 아직 경험한 것이 많이 없기 때문에 생각할 수 있는 범위가 좁다. 하지만 오늘도 이 과제를 하면서 나의 경험치가 조금 더 높아졌다. 이 과제를 하면서도 앞으로 해야 할 것들이 늘어만 가지만 내가 내는 많은 에러와 함께 나 자신이 발전해 나가는 모습을 보니 너무 감사하다.3. 소스※ 전화번호부 만들기//main.cpp#include "PhoneBook.h"// 초기값 세팅void basePhoneBook(PhoneBook &pb1, PhoneBook &pb2){string inputNames[] = {"Park SH", "Kang JH", "Kim KS", "Lee YH", "Kang SH","Bae JM", "Lee DI", "Lee BH", "Chang WH", "Chun WY"};int inputNumbers[] = {5023, 5002, 5008, 5067, 5038, 5381, 5125, 5165, 5684, 5752};for (int i=0; i
0. 문제정의※ 연산자 overloading하기- 지난번 과제에서 만든 프로그램을 사용한다. >>> 전화번호부- 입력, 삭제, 검색이 가능해야 한다.- 검색의 경우 최소한 이름으로 번호 찾는 부분과 번호로 이름을 찾는 부분이 필요하다.- list에서 사용되는 주요 기능 중 next(), previous(). get() 함수를 ++ (nex)), --(previous),*(get)을 사용하여 프로그램 작성이 가능하도록 한다.1. 문제해결※ 연산자 overloading하기● 연산자 다중정의란?● 이미 정의된 연산자에 프로그래머가 새로운 의미를 부여하는 것을 의미한다. 또한 연산자 사이의 우선순위와 결합 순서는 그 언어에 의해 고정되어 있으며 이를 변경시킬 수는 없다. 구현하는 방법에는 클래스 정의와 별개인 외부함수로 구현하거나, 클래스 정의부 내에서 멤버 함수로 정의될 수 있다.● 방법 : return_type operator연산자(인자1,인자2...){ return_type ...};● 리스트 구현● node : 리스트에서 각각의 데이터를 나타내는 것으로 데이터와 이전 값의 주소, 다음 값의 주소를 가지고 있다. 만약 이전과 다음이 null이라면 이 노드는 아직 연결되지 않은 객체이다.● iderator : 리스트에서 현재 위치를 가지고 있는 포인터이다. 기본적으로 다음, 이전으로 이동할 수 있는 기능과, 현재 값을 반환해주는 기능, 그리고 비교를 위한 다른 이터레이터와 비교하는 기능이 있어야 한다.● list : 맨 뒤에 데이터(노드)를 넣는 기능, 현재 이터레이터 앞에 데이터(노드)를 삽입하는 기능, 현재 이터레이터가 가지고 있는 데이터를 삭제하는 기능, 이터레이터의 위치를 처음으로 알려주는 기능, 이터레이터의 위치를 맨 끝으로 알려주는 기능이 필요하다. list에서는 처음과 끝의 위치를 알아야 한다. 그래서 처음 값의 주소와 마지막의 주소를 가지고 있는다.● 전화번호부는 클래스로 정의된 자료구조로 string형의 이름과 int 형의 전화번호로 구성되어있다.● 전화번호부에 사용되는 함수는 외부함수로 구현 한다. 여기에는 전체리스트 출력, 이름으로 검색, 번호로 검색, 초기 전화번호부 만들기, 하는 부분이 있어야 한다. 삭제하는 부분은 list에 있는 삭제하는 기능을 이용하고, 추가 입력하는 부분은 list의 push_back를 이용한다.● 다음, 이전 함수는 iterator에만 있는 기능이며, 이터레이터에서 새로 만드는 것이 간편하다. 따라서 연산자 다중정의를 통해 ++, -- 등을 하려면 이터레이터에서 멤버 변수를 추가해 주면 된다.● 전위++은 지금 현재 이터레이터 위치를 다음으로 옮기고 자기 자신을 반환해주면 된다. 후위++은 멤버 함수 내에서 자기 자신을 가지는 변수를 하나 선언한 후에 전위++을 실행해서 선언된 변수를 반환하면 된다.● 전위--는 지금 위치가 null이 아닌지 확인 후에 null 이라면 이터레이터의 현재위치를 맨 마지막으로 바꾼다. 그것이 아니라면 현재 위치를 이전위치로 바꾸고 자기 자신을 반환한다. 후위--는 후위++과 하는 방법이 동일하다.● 이터레이터가 가지고 있는 값 반환하는 함수의 경우 포인터라고 볼 수 있다. 따라서 현재 위치가 null이 아니라면 현재 위치의 데이터를 반환해주면 된다. 여기에서 주의해야할 점은 이 프로그램에서는 반환형이 클래스란 것이다. 따라서 외부에서 *을 사용해서 내용을 받으려고 해도 클래스 객체를 하나 선언한 후에 그 객체에서 내부의 이름과 전화번호를 접근해야 한다.2. 결론이번 과제의 경우 기존의 프로그램을 그대로 사용하면서 연산자 부분만 추가하면 되는 프로그램이었다. 그냥 책으로 봤을 때는 할 수 있겠다고 생각했었는데 실제로 구현해보니까 생각만큼 쉽지 않았다. linked list의 경우 노드와 이터레이터와 리스트, 그리고 자료형 클래스까지 네 개의 클래스를 동시에 사용하기 때문에 각각의 관계를 생각하는 것이 가장 어려웠다.연산자를 재정의 할 수 있다는 것이 신기했다. 수업을 할 때 필기를 열심히 한다고 했었는데, 이번 과제를 하면서 개념이 이해가 안 되어서 강의 자료를 찾아보았지만... 전위연산자와 후위연산자 구현 시 왜 그렇게 되는지 아직 이해가 잘 안 된다. 후위 연산자가 구현할 때 더 많은 메모리를 사용하고, 더 많이 동작한다는 것 밖에는... 후위연산자를 구현하는 부분에서 함수 내부에서 바꾼 이터레이터의 값이 변하지 않아서 한참을 고생했다. 출력하는 부분에서 계속 첫 번째 값만 출력하는 무한루프가 되었다. 함수에서 인자를 넘기는 것에는 두 가지 방법이 있다는 것을 잊어버리고 그냥 함수 내부에서 종료해 버려서 실제로 프로그램이 동작하는 부분에서는 값이 바뀌지 않았던 것이다. *this를 사용해서 자기 자신을 가르치면서 이 안에서 다시 전위 연산자를 호출하니까 제대로 실행되었다. 또한 연산자 재정의시 operator와 연산자(+, -, *, / 등)사이에 공백이 있으면 안 된다는 점에서 에러를 냈다. 한참을 끙끙거리고 인터넷을 뒤져본 결과 정의할 때 공백이 있으면 안 된다고 한다. 컴파일러의 세계는 오묘하고 신기한 듯 하다.get 함수를 *로 바꾸는 과정에서도 애를 먹었다. 포인터의 개념이 정확하게 정립되어 있지 않았기 때문이다. 반환형이 클래스 형에 여러 개의 자료가 들어있는 형태라면 객체명. 멤버를 사용해서 출력을 해야 하는데, 나는 단순히 객체를 *을 붙여서 출력하려고 하니까 에러가 났던 것이다. cout을 사용하면 < 연산자와 함께 사용해야 하는데, 정확하게는 모르겠지만 포인터나.. 이런 것에서도
0. 문제정의※ array와 vector로 전화번호부 만들기- 전화번호부는 단축키, 이름, 번호, 메모로 구성된다.- 입력, 삭제, 검색이 가능해야 한다.- 검색의 경우 최소한 이름으로 번호 찾는 부분과 번호로 이름을 찾는 부분이 필요하다.1. 문제해결※ 전화번호부 만들기● 전화번호부 하나의 데이터는 각각 변수를 선언하여서 작성하기보다 구조체로 변수를 묶어서 작성하는 것이 편리하다. 이렇게 작성할 수 있는 방법에는 구조체(struct)와 클래스가 있다. 배열로 만든 프로그램에서는 구조체를, vector를 사용하여 만든 프로그램에서는 클래스를 사용하기로 한다.● 전화번호부는 사용자가 종료버튼을 입력하기 전까지 계속 유지된다. 따라서 command를 만들어서 사용자로부터 해당 명령어 값을 입력받아서 입력, 수정, 삭제, 검색 등의 기능이 되게 한다.● 입력, 삭제 등의 기능에서는 사용여부를 저장하고 있는 변수를 구조체의 멤버로 넣어서 작성하도록 한다. 물론 입력, 삭제 등이 이루어지면 다른 모든 데이터를 올리거나 내리거나 하는 방법도 있지만 이렇게 하게 되면 프로그램 상에서 불필요한 동작이 생기게 되므로 사용여부 필더에 사용으로 되어있으면 사용하는 것이고, 아닐 경우 사용하지 않는 필더로 검색, 삭제가 불가능하며, 입력만 가능하게 하는 것이다.● 입력하는 함수의 경우 지금 사용하지 않는 번지수를 찾는 것이 필요하다. 만약 사용여부를 저장하는 필더에 저장된 값이 정렬할 수 있는 것이라면 sort방법 중 빠른 방법을 사용하면 된다. 하지만 지금 작성하는 전화번호부는 정렬을 하지 않는다. 따라서 전화번호부 시작위치부터 읽어서 사용하는 번지수는 건너 띄고 사용하지 않는 번지수를 찾아서 그 번지에 데이터가 입력되게 프로그램을 만든다면 메모리 낭비를 하지 않을 수 있다.● 검색함수도 입력함수와 비슷하다. 이름으로 검색해서 번호가 뜨고, 번호로 검색해서 이름이 떠야 한다. 그리고 사용되지 않고 있는 값은 출력되면 안 되고 에러처리를 해주어야 한다. 또한 이 검색함수에서 반환되structor와 function을 합친 것이므로 구지 따로 빼서 관리할 필요가 없다. 단지 클래스의 각 데이터가 될 구조체 하나를 선언한 후에 그 구조체형의 vector object를 선언하면 보다 가독성이 높은 프로그램이 된다.2. 순서도● array로 만든 전화번호부 프로그램과 vector로 만든 전화번호부 프로그램은 데이터 형만 다른 같은 구조 사용한다. 따라서 순서도는 vector로 만든 전화번호부 프로그램만 작성한다.※ vector로 만든 전화번호부// main.cpp3. 결론전화번호부를 만드는 과정에서도 이렇게 많은 기능이 들어간다는 사실을 다시 한 번 깨닫게 된다. 사용할 때에는 별것 아닌 것 같아 보이는 프로그램인데도 복잡한 프로그래밍이 들어간다는 사실에서 앞으로 가야 할 길이 먼 것을 느낀다.가장 어려웠던 부분은 역시 문제를 정의하고 문제 해결을 위한 개념을 잡는 부분이었다. 겉으로 드러난 부분 뒤에 숨겨진 보이지 않는 부분을 찾는 1인치가 가장 어려운 부분이었다. 물론 정확한 업무를 파악하지 못하고 있기 때문이다. 회사에 다닐 때도 매우 간단한 일인데도 업무정의가 제대로 되어있지 않아서 고생을 꽤나 한 적이 있다. 프로그램도 마찬가지 인 것 같다. 프로그램 작성자가 업무를 정확하게 파악하고 있어야 보다 빠르게 프로그램을 작성할 수 있는 것이라 생각된다. 사실 1학년 때 과제까지는 일단 대충 머릿속으로 생각한 다음 코딩부터 들어갔는데 2학년 올라와서 접하게 되는 과제들은 단순히 머릿속으로만 생각하기가 버겁다. 꼭 손으로 적어서 정확하게 문제를 정의해야 한다.vector로 전화번호부 만들기란 과제를 할 때 먼저 배열로 만들고 그 후에 vector로 만들었다. 처음에 배열로 전화번호부를 만들 때는 정확한 개념이 파악되지 않아서 오래 걸렸다. 하지만 정식 과제인 벡터로 전화번호부를 만드는 과정에서는 보다 빠른 시간동안에 프로그램을 작성 할 수 있었다. 만약 배열로 만들었을 때에도 함수로 따로 구현한 것이 아니라 main안에서 되게 했다면 프로그램을않는다면 훗날 제대로 된 전화번호부를 만들 수 없을 것이라는 생각을 한다.좋은 프로그램이라는 것은 메모리를 적게 사용하고, 동작 시간이 빨라야 된다고 여러 교수님들과 선배들이 말한 내용이었다. 이 과제를 하기 전까지는 개념이 잘 잡히지 않았었는데 array와 vector 두 가지 방법으로 프로그램을 작성해 본 결과 이제 프로그램이 점점 메모리를 유동적으로 사용하는 방법으로 간다는 생각을 한다. 지금은 좋은 프로그램을 작성하지 못하지만 최고가 되는 그날까지 한 걸음 한 걸음 해쳐나가려고 한다.4. 소스※ array로 만든 전화번호부#include #include using namespace std;#define MAX 100// 전화번호부 구조체 정의struct phone_book{int key; // 단축키string name; // 이름string phone; // 전화번호string memo; // 메모bool use_yn; // 사용여부};void Func_Input(struct phone_book a[]); // 입력void Func_Delete(struct phone_book a[]); // 삭제int Func_Search(struct phone_book a[]); // 검색int Func_SpeedNumber_Search(struct phone_book a[]); // 사용하지 않고 있는 단축번호 찾기void Func_Print(struct phone_book a[], int key); // 전화번호부 출력void main(){cout < "배열로 전화번호부 작성하기 " < endl;cout < "--------------------------------------------" < endl;cout < ":::::::::::::: 전화번호부 ::::::::::::::::" < endl;struct phone_book ph_book[100]; // 배열로 작성하는 전화번호부. 기본 100개.// 단축키와 사용여부 초기화for(int i = 0; i <t < "--------------------------------------------" < endl;cout < "실행할 메뉴 입력 : ";cin >> summary;switch(summary){case('i') :case('I') : Func_Input(ph_book); break;case('D') :case('d') : Func_Delete(ph_book); break;case('s') :case('S') : Func_Search(ph_book); break;case('p') :case('P') : Func_Print(ph_book,-1); break;case('q') :case('Q') : cout < "---------------" < endl;cout < " 프로그램 종료 " < endl; return;default : cout < "error!! 잘못된 메뉴입력“ < endl; break;} //switch case 문 종료}// while 문종료}// 입력하는 함수void Func_Input(struct phone_book a[]){int i = Func_SpeedNumber_Search(a); // 단축번호 되돌려 받기a[i].key = i;cout < "단축번호 " < i < endl;cout < "이름입력 : ";cin >> a[i].name;cout < "번호입력 : ";cin >> a[i].phone;cout < "메모입력 : ";cin >> a[i].memo;a[i].use_yn = true;};// 삭제하는 함수void Func_Delete(struct phone_book a[]){int tmp = Func_Search(a);if(tmp >= 0)cout < "삭제되었습니다.(단축번호 : " < tmp < ")" < endl;elsecout < "에러!! 없는 번호/이름 입니다." < endl;//cout < tmp < endl;a[tmp].use_yn = false;Func_Print(a,-1);};//검색해서 index 넘겨주는일한 이름이고 사용중cout < "검색결과 : " ;Func_Print(a,i);return i;}i++;}//while문 종료if(i == MAX){ // 검색 결과가 없는 경우cout < "검색 실패 - 데이타가 없습니다." < endl;return -1;}}else{// 번호로 검색하는 부분i = 0;while(i < MAX){if(a[i].phone == search && a[i].use_yn == true){ // 동일한 번호이고 사용중cout < "검색결과 : " ;Func_Print(a,i);return i;}i++;}//while문 종료if(i == MAX){ // 검색 결과가 없는 경우cout < "검색실패 - 데이타가 없습니다." < endl;return -1;}}return -1;};// 사용않는 단축번호 검색int Func_SpeedNumber_Search(struct phone_book a[]){int key = 0;while(true){if(a[key].use_yn == false)return key;elsekey++;}return -1;}// 전화번호부 출력void Func_Print(struct phone_book a[], int key){// key --> positive number : phone_book[number] data print// --> negative number : all phone_book data printif(key >= 0){ // print에 바로 인덱스가 인자로 입력된 경우, 해당 인덱스만 출력cout < "단축번호 : " < a[key].key < " ";cout < "이 름 : " < a[key].name < " ";cout < "전화번호 : " < a[key].phone < " ";cout < "메 모 : " < a[key].memo < " " < endl;}else if(key < 0){ // print 함수 호출시 음수로 입력된 경우, 전체의 전화번호부 출력cout < " ::::: 현재 저장
0. 문제정의※ 카드 정렬을 통한 String 구현 및 사용하기- 기본적으로 표준 STL로 구현된 카드 프로그램을 제공한다.- 제공받은 카드 정렬 프로그램을 구현한 String 객체로 바꾼다.- 구현한 String의 경우 일반적으로 알고 있는 string 객체의 연산자가 제공되지 않는다.따라서 기본적인 string의 기능과 연산은 알고 있으며, 이를 재정의 할 수 있어야 한다.1. 문제해결※ 카드 정렬을 통한 String 구현 및 사용하기● 연산자 다중정의란?● 이미 정의된 연산자에 프로그래머가 새로운 의미를 부여하는 것을 의미한다. 또한 연산자 사이의 우선순위와 결합 순서는 그 언어에 의해 고정되어 있으며 이를 변경시킬 수는 없다. 구현하는 방법에는 클래스 정의와 별개인 외부함수로 구현하거나, 클래스 정의부 내에서 멤버 함수로 정의될 수 있다.● 방법 : return_type operator연산자(인자1,인자2...){ return_type ...};● 리스트 구현● node : 리스트에서 각각의 데이터를 나타내는 것으로 데이터와 이전 값의 주소, 다음 값의 주소를 가지고 있다. 만약 이전과 다음이 null이라면 이 노드는 아직 연결되지 않은 객체이다.● iderator : 리스트에서 현재 위치를 가지고 있는 포인터이다. 기본적으로 다음, 이전으로 이동할 수 있는 기능과, 현재 값을 반환해주는 기능, 그리고 비교를 위한 다른 이터레이터와 비교하는 기능이 있어야 한다.● list : 맨 뒤에 데이터(노드)를 넣는 기능, 현재 이터레이터 앞에 데이터(노드)를 삽입하는 기능, 현재 이터레이터가 가지고 있는 데이터를 삭제하는 기능, 이터레이터의 위치를 처음으로 알려주는 기능, 이터레이터의 위치를 맨 끝으로 알려주는 기능이 필요하다. list에서는 처음과 끝의 위치를 알아야 한다. 그래서 처음 값의 주소와 마지막의 주소를 가지고 있는다.● card image는 string type으로 정의 되어있다. 그리고 카드 순서 별로 정렬되어있다. 이 과정에서 섞는 함수와 프린트 함수, 소팅 함수가 들어있다.● STL의 string을 사용자 구현 String으로 바꾸어 준다. string이 들어간 모든 부분이 String으로 바꾸어 주어야 한다. 자료 추상화에 의해서 string이 String으로 바뀌어도 외부 구현은 정상적으로 동작되어야 한다.● 연산자 다중정의 부분에서 compare함수를 통해 자기 자신과 다른 String 객체를 비교한다. compare 함수는 두 값 사이의 차를 가지고 -1, 0, 1을 반환하는데 각각의 값에 따라서 등호가 결정된다. 이렇게 compare 함수만 구현한다면 erase(iter1);}while (!L2->empty()) {L->push_back(iter2.get());iter2 = L2->erase(iter2);}}void mergeSort (List* L){int n = L->size();if (n < 2)return;List* L1 = new List();List* L2 = new List();int i = 0;Iterator li = L->begin();while (i < n/2) {L1->push_back (li.get());li = L->erase(li);i++;}while (li != L->end()) {L2->push_back(li.get());li = L->erase(li);}mergeSort(L1);mergeSort(L2);merge(L1, L2, L);}int irandom (int low, int high) {float r = (float)rand();float rmax = RAND_MAX;return (int)((r/rmax)*(high - low + 1) + low);}void suffle (List* L){srand((int)time(0));int oneOrzero = 0;int lsize = L->size();Iterator iter = L->begin();for(int i = 1; i < SUFFLECOUNT*lsize; ++i){oneOrzero = irandom(0,1);if(oneOrzero == 0){//move to backL->push_back(iter.get());iter = L->erase(iter);}else{iter.next();if(iter.equals( L->end()))iter = L->begin();}}}int main()//int argc, char* argv[])//_tmain()//int argc, _TCHAR* argv[]){List deck;// Make a Card Deckfor (int s=CLUB; s
0. 문제정의※ 구현한 list로 전화번호부 만들기- 전화번호부는 단축키, 이름, 번호, 메모로 구성된다.- 입력, 삭제, 검색이 가능해야 한다.- 검색의 경우 최소한 이름으로 번호 찾는 부분과 번호로 이름을 찾는 부분이 필요하다.1. 문제해결※ 전화번호부 만들기● 전화번호부 하나의 데이터는 각각 변수를 선언하여서 작성하기보다 구조체로 변수를 묶어서 작성하는 것이 편리하다. 이렇게 작성할 수 있는 방법에는 구조체(struct)와 클래스가 있다. 이 프로그램에서는 클래스를 사용하기로 한다.● 전화번호부는 사용자가 종료버튼을 입력하기 전까지 계속 유지된다. 따라서 command를 만들어서 사용자로부터 해당 명령어 값을 입력받아서 입력, 수정, 삭제, 검색 등의 기능이 되게 한다.● 입력, 삭제 등의 기능에서는 사용여부를 저장하고 있는 변수를 구조체의 멤버로 넣어서 작성하도록 한다. 물론 벡터에서는 입력, 삭제를 할 경우에 사용여부라는 필더를 체크해서 입력, 삭제를 하였다. 하지만 리스트에서는 사용여부라는 대상이 필요 없이 바로 해당 위치에 삽입, 삭제를 하면 된다. 그러기 위해서 필요한 것이 iterator라는 기능이다. 이 iterator라는 기능은 리스트 내에서 현재의 위치를 아는데 필요하다.● 입력하는 함수와 삭제하는 함수에서는 vector로 만든 전화번호부에서는 사용여부를 만들어서 불필요한 동작을 제거하였다. 하지만 리스트로 만드는 전화번호부에서는 그러한 사용여부를 체크하는 불필요한 동작 자체가 필요 없어진다. 리스트 내에서 바로 삭제하여 메모리 공간을 반납하면 되기 때문이다. 따라서 이미 추가한 후에 삭제하여 실제 메모리를 사용 중이지만 사용 중이지 않은 것처럼 보이는 것이 아니라 실제로 삭제 하는 것이기 때문에 더 효율적이라고 말 할 수 있다.● 검색함수에서 이름으로 검색하면 전화번호가 나오고, 전화번호로 검색하면 이름이 나와야 한다. 단순히 검색만 하는 로직에서는 문제가 되지 않는다. 하지만 삭제하는 로직에서는 여기에서 검색된 것으로 해당 라인 자체를, 처음과 끝을 알려주는 기능이 필요하다.● iterator는 list 구현 시 매우 중요한 역할을 하는데, 바로 주소 값으로 표현되는 리스트에서 현재 위치를 알려주기 때문이다. 여기에 필요한 기능으로는 itearator의 앞, 뒤를 아는 것과, 현재 위치하고 있는 데이터의 값을 나타내는 것, 그리고 다른 이터레이터와 비교해서 같은지 판별하는 것이 필요하다.● cell의 경우 그냥 하나의 세포라고 보면 된다. 여기에서는 실제적으로 데이터를 저장하고, 해당 노드의 앞과 뒤에 위치하고 있는 것이 무엇인지 포인터하고 있는 것이 필요하다.2. 결론지난 번 과제는 vector에서 전화번호부 구현이었는데, 이번 과제는 내가 구현한 list를 사용해서 전화번호부 프로그램을 구현하는 것이다. 작년에 배운 내용이었지만 다시 list를 구현하는 것은 꽤나 어려운 일이었다. 처음에 과제를 시작할 때에는 리스트의 개념이 잘 잡히지 않아서 개념을 잡는 것부터 시작했다. 아니 아직도 잘 모르겠다. 좋은 프로그램을 만들기 위해서는 만들어 놓은 소스를 수정하는 연습도 해야 할 것 같다. 불과 일주일밖에 안 지났지만 내가 만들어 놓은 소스를 다시 보는 것은 참 어려운 일이다. 한글은 읽을 수라도 있지, 프로그램은 알고리즘과 왜 이걸 이렇게 만들었는지를 모두 알아봐야 했기 때문이다.처음에 이 과제를 시작하면서 기존에 있는 프로그램을 그냥 하면 된다고 생각하여 미루고 미루다가 전날 급하게 만들려고 하니 부족한 부분이 많이 보인다. 학부에서 간단한 프로그램을 작성하는 것도 이렇게 미루고 있는데... 나중에 어떻게 일을 할지 매우 걱정이 된다. 앞으로는 문제 혹은 사용자의 요구조건이 생기면 바로바로 하는 습관을 길러야한다. 미루다 보면 쌍방향에 좋은 일이 아닐 것이라는 생각이 든다.사람의 뇌는 모든 것을 기억하지 못하기 때문에 분쟁이 생긴다. 그리고 그렇기 때문에 문제 해결에 더 많은 시간이 걸리는 지도 모른다. (물론 그 때문에 아픈 기억을 잊을 수 있기에... 얼마나 창조주께 감사드리는지 모른서 잘못 작성한 여러 프로그램보다 잘 작성한 하나의 프로그램이 백번 낫다는 생각을 한다. 그리고 그런 잘 작성하는 프로그램을 만들기 위해서 지금도 한걸음씩 전진하고 있다. 갈 길이 멀지만 천릿길도 한걸음부터 시작하는 내가 되어야 겠다.앞으로 나에게는 문제를 작게 나누는 능력과, 되도록 간단하게 프로그램을 작성하는 방법 연구가 필요하다고 느껴진다. 이번 과제를 통해서 나를 다시 한 번 돌아보게 해주신 교수님께 감사드린다.3. 소스※ list로 만든 전화번호부 - 수정한 부분의 소스만//main.cpp#include #include #include #include using namespace std;class List;class Iterator;class Entry {public:Entry(){}Entry(string s, int n) {name = s; phone_number = n;}string name;int phone_number;};string Names[] = {"Park SH", "Kang JH", "Kim KS", "Lee YH", "Kang SH","Bae JM", "Lee DI", "Lee BH", "Chang WH", "Chun WY"};int Numbers[] = {5023, 5002, 5008, 5067, 5038, 5381, 5125, 5165, 5684, 5752};class Node{public:/* Constructs a node with a given data value.@param s the data to store in this node*/Node(Entry s);private:Entry data;Node* previous;Node* next;friend class List;friend class Iterator;};class List{public:/**Constructs an empty list;*/List();/** Appends an element to the list.@param s the value to append*/er theerased element*/Iterator erase(Iterator i);/** Gets the beginning position of the list.@return an iterator pointing to the beginning of the list*/Iterator begin();/**Gets the past-the-end position of the list.@return an iterator pointing past the end of the list*/Iterator end();private:Node* first;Node* last;};class Iterator{public:/** Constructs an iterator that does not point into any list.*/Iterator();/**Looks up the value at a position.@return the value of the node to which the iterator points*/Entry get() const;/**Advances the iterator to the next node. */void next();/**Moves the iterator to the previous node. */void previous();/**Compares two iterators@param b the iterator to compare with this iterator@return true if this iterator and b are equal*/bool equals(Iterator b) const;private:Node* position;Node* last;friend class List;};Node::Node(Entry s){ data = s;previous = NULL;next = NULL;}List::List(){ first = NULL;last = NULL;}void List::push_back(Entry s){ Node* newnode = ->previous;Node* newnode = new Node(s);newnode->previous = before;newnode->next = after;after->previous = newnode;if (before == NULL) /* insert at beginning */first = newnode;elsebefore->next = newnode;}Iterator List::erase(Iterator i){Iterator iter = i;assert(iter.position != NULL);Node* remove = iter.position;Node* before = remove->previous;Node* after = remove->next;if (remove == first)first = after;elsebefore->next = after;if (remove == last)last = before;elseafter->previous = before;iter.position = after;delete remove;return iter;}Iterator List::begin(){Iterator iter;iter.position = first;iter.last = last;return iter;}Iterator List::end(){Iterator iter;iter.position = NULL;iter.last = last;return iter;}Iterator::Iterator(){position = NULL;last = NULL;}Entry Iterator::get() const{assert(position != NULL);return position->data;}void Iterator::next(){assert(position != NULL);position = position->next;}void Iterator::previous(){if (position == NULL)position = last;elseposition = posit0; i