2012 Ds 03

21
project #3 다항식 연산 자료구조 조장: 20113311 장동규 조원: 20113309 이태구 20113318 정예린 20113315 정민정 20083657 서영진

Transcript of 2012 Ds 03

Page 1: 2012 Ds 03

project #3

다항식 연산

자료구조

조장:

20113311 장동규

조원:

20113309 이태구

20113318 정예린

20113315 정민정

20083657 서영진

Page 2: 2012 Ds 03

순서

•조원별 업무분담

•일정 계획-회의록

•문제 파악-Linked List라는 자료구조를 활용하여

다항식 연산

•알고리즘 계획

•소스구현

•문제점 파악 / 해결법 토의

•최종소스

•시간 복잡도/공간 복잡도

Page 3: 2012 Ds 03

이름 역할

장동규 조장, 보고서 작성, 자료 조사

정예린 코딩, 자료 조사

정민정 알고리즘, 자료조사

서영진 보고서 작성, 자료 조사

날짜 계획

04.12~04.17링크드 리스트, 다항식 연산에 대해 조사

해오기, 보고서 작성

04.17~04.19

링크드 리스트 소스 구현하는 알고리즘, 이

것을 어떻게 다항식 연산에 활용할 것인지

생각 해오기, 보고서 작성04.19~04.24 알고리즘을 소스로 구현, 최종 보고서 작성

1) 조원별 업무 분담

2)일정계획

Page 4: 2012 Ds 03

3)문제파악

링크드 리스트(Linked List)

배열 구조의 단점을 보안한 자료구조이다. 배열은 인덱스를 이용하여 해당 주소에 바로 접

근할 수 있는 장점이 있지만, 단점으로는 삽입, 삭제 연산이 복잡하다. 그리고 배열은 선언

시 크기를 미리 정해줘야 하기 때문에 배열 공간 100개를 선언해 놓고 10개만 쓰는 경우

(메모리 낭비), 200개가 필요한 경우(공간 부족) 라면 배열 선언 부분을 다시 수정해줘야 하

는 불편함이 있다.

이러한 단점을 보안해 필요할 때 마다 공간을 할당하고 또 그것들을 연결하여 마치 배열처

럼 사용하는 기법이 바로 링크드 리스트이다.

링크드 리스트의 장점으로는 프로그래머가 미리 공간을 할당할 필요 없이 필요할때마다 공

간을 할당 받을 수 있도록 설계가 가능하다. 그러기 때문에 필요한 변수의 크기를 모를 경

우에는 배열보다 효율적이다. 하지만 링크드 리스트에도 단점은 있다. 다음 노드의 주소를

가리키기 위해 4byte(32비트 운영체제 기준)의 공간이 낭비된다. 또, 인덱스로 해당 주소에

접근하는 것이 아닌 노드의 첫 번째를 가리키는 Head라는 포인터 변수를 통해서 순차적으

로 접근하는 단점으로 인해 검색속도가 느리다는 단점이있다.

(3번지 주소까지 가기 위해서는 1, 2번 주소지를 거쳐야 갈 수 있다.)

Page 5: 2012 Ds 03

다음은 링크드 리스트를 구현한 소스이다.

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

typedef struct tagNode{

char Name[20];

struct tagNode* NextNode;

}NODE;

구조체로 이루어져 있는 링크드 리스트. Name은 데이터를 담을 변수로 데이터가 들어가

며, tagNode*는 다음 노드의 주소를 가리킬 포인터 변수이다.

NODE* CreateNode(char name[])

{

NODE* NewNode = (NODE*)malloc(sizeof(NODE));

strcpy(NewNode -> Name, name);

NewNode -> NextNode = NULL;

return NewNode;

}

NODE를 생성하는 함수이다. 인자로는 해당 노드에 들어갈 값을 저장하기 위한 값을 받고

있다. NewNode라는 포인터를 생성후 그 해당하는 주소에 malloc함수로 공간을 동적할당하

고 있다.

void ConnectNode(NODE** Head, NODE* Node)

{

if(NULL == (*Head))

Page 6: 2012 Ds 03

{

*Head = Node;

}

else

{ NODE* Current = *Head;

while(Current -> nextNode != NULL)

{

Current = Current -> NextNode;

}

Current -> NextNode = Node;

}

}

인자로는 첫 노드를 가리키는 Head의 주소값과 연결한 노드를 인자로 받는다. 여기서 헤

드가 가리키는 노드가 없는(NULL)새로운 노드라면, main에 선언한 Head값 자체를 바꾸기

위해 포인터 Head의 주소값을 가져오기 때문에 결과적으론 이중 포인터를 사용해야 한다.

노드의 맨 마지막에 삽입할 경우의 수는 두 가지가 있다.

1. Head가 NULL일 경우(텅 빈 노드)

2. Head가 NULL이 아닐 경우(하나 이상의 연결된 노드)

1번의 경우는 Head의 다음 노드에 새 노드의 주소값을 넣으면 되지만, 2번의 경우엔 끝

노드를 찾아서(NULL이 있는곳) 연결 해 줘야 한다. NODE* Current;를 선언하는 이유는

Head의 값을 바꾸지 않고 연결된 다른 노드에 접근하기 위해서 사용한다.

void PrintNode(NODE* Head, int index)

{

NODE* Current = Head;

Page 7: 2012 Ds 03

while(Current != NULL && 0 < index)

{

index--;

Current = Current -> NextNode;

}

printf(“%s\n”, Current -> Name);

}

노드의 값을 출력하는 함수이다. 인자로는 Head와 몇 번째 노드를 출력할건지 정하는 변

수이다. while의 경우 Current != NULL은 NULL일 경우엔 노드의 끝이므로 이 이상 접근을

하지않기 위해 쓴다.

int GetCountNode(NODE * Head)

{

NODE* Current = Head;

int count = 0;

while(Current != NULL)

{

count++;

Current = Current -> NextNode;

}

return count;

}

PrintNode로 전체 출력을 하기를 원할 경우 노드의 개수를 알아내는데 사용되는 함수이다.

void InsertNode(NODE** Head, NODE* ConnectNode, int index)

{

if(0 == index)

Page 8: 2012 Ds 03

{

ConnectNode -> NextNode = (*Head);

*Head = ConnectNode;

}

else

{

NODE* Current = *Head;

while(0 < (--index))

{

Current = Current -> NextNode;

}

ConnectNode -> NextNode = Current -> NextNode;

Current -> NextNode = ConnectNode;

}

}

노드와 노드 사이에 새로운 노드를 삽입하는 함수이다.

1. 4번지 주소의 다음 노드 주소값을 2번지 노드의 주소값으로 변경

2. 2번지 노드의 주소값을 4번지 노드의 주소로 변경

void DestroyNode(NODE** Head, int index)

{

NODE* Remove = *Head;

while(Remove != NULL && 0<(--index))

Page 9: 2012 Ds 03

{

Remove = Remove -> NextNode;

}

if(*Head == Remove)

{

*Head = Remove -> NextNode;

}

else

{

NODE* Current = *Head;

while(Current != NULL && Current -> NextNode != Remove)

{

Current = Current -> NextNode;

}

if(Current != NULL)

{

Current -> NextNode = Remove -> NextNode;

}

}

free(Remove);

}

삭제 연산은 삽입 연산보다 훨씬 간단하다. 삭제할 노드의 앞노드(1번노드)의 다음 주소를

삭제할 노드의 다음 주소를 가리키도록만 하면 된다.

프로그래머가 할당하는 공간은 프로그래머가 해제해 줘야한다. 그러기 위해서 사용하는 함

수 free가 있다. 인자는 해제할 메모리의 주소값만 넘기면 되기 때문에 삭제할 노드의 주소

를 보내주면 된다.

구조체

다른 종류의 데이터를 하나로 묶어서 사용하는 데이터 결합법을 말한다.

각기 다른 형이나 다른 의미의 값을 가지고 있는 배열들을 한 번에 나타낼 수 있도록 구현

한 자료구 조형이다.

Page 10: 2012 Ds 03

DATA LINK

계수부분 지수부분

struct 구조체 이름

{

자료형 자료이름;

자료형 자료이름;

}

과 같이 정의 할 수 있으며, 정의를 할 때에는 다음의 조건이 따른다.

①구조체 정의에서 바로 초기화 할 수 없다.

②구조체 선언은 문자에 해당되기 때문에 끝마친 후 ;을 붙여 주어야 한다.

구조체를 통해서 여러개의 테이타 값을 묶을 수 있게 하여 연결리스트를 구현 할 수 있도록

한다.

4)알고리즘 계획

① 다항식의 표현

1) 각 노드의 구조체 배열에서 DATA를 저장하는 배열과 다른 노드를 가리킬 수 있는 LINK

가 존재한다. 이 때 DATA는 처리하는 값을 저장하는 배열이고, LINK는 다음 노드를 가리키

는 포인터의 역할을 한다.

다항식을 구현하기 위해서는,

2) 다항식의 각 항을 계수부분 지수부분으로 나누어 생각한다.

DATA의 배열도 계수와 지수를 저장할 수 있는 구조체를 선언한다.

Page 11: 2012 Ds 03

D A T A - 계수부분

DATA-지수부분 LINK

즉,

과 같이 한 노드가 만들어지게 된다.

3) 이러한 노드를 다항식에서 항의 개수만큼 LINK를 이용해 다음 항을 가리키고 다음 항을

가리키는 식으로 한 개의 다항식에 대해 한 개의 연결리스트를 만들어준다.

② 다항식의 덧셈과 뺄셈

1) 연결리스트로 작성 된 다항식1과 다항식2에 대해서 지수부분이 같은 노드끼리 연산을 해

준 다.

2) 다항식 3을 연결리스트로 작성하게 되는데, 이 때 1과2로 연산된 값을 3에 저장한다.

3) 1과 2에 같은 지수부분이 없어서 연산되지 않은 나머지 항들은 그대로 복사되어서 3에

저 장된다.

4) 다항식의 연산을 마쳐서 3에 저장된 결과 값을 출력한다.

③ 다항식의 곱셈

1) 다항식 1의 노드와 다항식2의 노드의 계수부분은 곱셈연산을 하고 지수부분은 더하기 연

산 을 해준다.

2) 다항식1의 노드와 다항식2의 노드는 서로의 노드가 모두 순서쌍을 한 번 씩은 이루어야

된 다.

3) 순서쌍을 이루어서 연산 된 결과 값은 새로운 연결리스트 3에 저장된다.

4) 각 노드들을 모두 더할 수 있도록, 위에서 작성하였던 ADD연산을 한 번 더 해준다.

5) 정리 되어 3에 저장된 결과 값을 출력한다.

④ 다항식의 나눗셈

1) 나누는 다항식의 최고차항이 나눠지는 최고차항과 같아지게 할 수 있는 X가 계속해서 몫

이 될 수 있다.

2) 계수의 계산은,

p(x)의 계수 = s(x)계수*q(x) 계수, q(x)계수는 p/s과 같이 된다.

3) 계속 최고차항에 맞춰서 X가 곱해져서 나눠지는 다항식에 그 결과 값을 뺄셈을 하고 있

다.

이 때 곱해지는 차수가 0이거나 나머지가 0이면 스톱한다.

만약 뺄셈을 하다가 다항식이 남게 되면 그 남은 다항식은 나머지가 된다.

Page 12: 2012 Ds 03

5)소스 구현

①소스 분석

#include <stdio.h>

#include <stdlib.h>

typedef struct polynomial

{

int degree; //차수

double coef;//계수

struct polynomial *link;

}polynomial;

typedef struct node

{

int l;

polynomial *s;

polynomial *f;//다음을 가리킬 link

}node;

void st(node *point) //초기화

{

point->l=0;

point->s=point->f=NULL;

}

void insert_node(node *point,double coef,int degree)

{

//char *temp;

Page 13: 2012 Ds 03

polynomial *temp=(polynomial *)malloc(sizeof(node));//연길리스트의 메모리할당을

temp의 포인터 옮기는 정도에 따라 할당해줌

if(temp==NULL)

{

exit(1);

}

temp->coef=coef;//포인터로 polynomial타입의 구조체를 불러와서 계수를 삽입

temp->degree=degree;//차수를 삽입

if(point->f==NULL)//만약 연결리스트에서 빈값을 만나면 다시 temp로 포인터를 돌

려줌

{

point->s=point->f=temp;

}

else//그 이외의 경우 point는

{

point->f->link=temp;

point->f=temp;

}

point->l++;//포인터를 길이만큼 증가해줘서 마지막 자리를 가리키도록 설정

}

/*void polynomial_add(node point1, node point2, node point3)

{

polynomial *a=point1->

*/

//다항식 출력

void print(node *point)

{

polynomial *p=point->s;//p포인터를 point를 통해 연결리스트의 처음 자리인s의

주소값을 받아옴

for(;p;p=p->link)

{

if(p->coef==0 || p->degree==0)//만약 계수나 차수가 모두 0이면 출력하

지 않음

{

printf("");

}

else if(p->degree==1)//차수가 1이면 계수만 출력

{

printf("%d",p->coef);

Page 14: 2012 Ds 03

}

else

{

printf("%dx^%d",p->coef,p->degree); //계수가나 지수가 0이 아니

면 계수x^지수 형태로 표시

}

if(p->link==NULL)//P가 가리킨 곳이 빈값이면 아무것도 출력하지 않음.

{

printf("");

}

else//값이 있는경우 가운데에 +를 출력

{

printf(" + ");

}

}

printf("\n");

}

void poly_add(node *plist1, node *plist2, node *plist3)

{

polynomial *a=plist1->s;//다항식 1을 탐색할 포인터

polynomial *b=plist2->s;//다항식 2를 탐색할 포인터

int sum;//계수를 담을 변수

while(a&&b)

{

if(a->coef == b->coef)//지수가 같은 경우

{

sum=a->coef+b->coef;//a,b 받은 계수과 차수를 coef구조체에 저

if(sum!=0)

{

insert_node(plist3,sum,a->degree);//삽입함수를 불러옴,

다항식1의 계수를 저장하는 polynomial구조체. 앞에서 계산 해준 sum은 계수로 저장.a는 다

항식1의 차수를 가리킴.

}

b=b->link;//둘다 연결리스트의 link를 가리키게 함.

a=a->link;

}

else if(a->degree >b->degree)

{

Page 15: 2012 Ds 03

insert_node(plist3,a->coef,a->degree);//차수를 가리키고 있을때,

다항식3번째=1+2의 결과값을 저장.

a=a->link;

}

else

{

insert_node(plist3,b->coef,b->degree);

b=b->link;

}

for(;a!=NULL;a=a->link)

{

insert_node(plist3,a->coef,a->degree);

}

for(;b!=NULL;b=b->link)

{

insert_node(plist3,b->coef,b->degree);

}

}

}

void main()

{

node list1, list2, list3; //다항식 입력받을 변수 선언

double a;

int b; //항의 계수와 지수를 입력받기 위한 변수

st(&list1);//st 함수 호출로 공백 리스트

st(&list2);

st(&list3);

//다항식1을 입력받는 부분

printf("다항식1의 항(계수,지수)을 입력하세요. (0 0 이면 입력종료)\n");

while (1)

{

scanf("%f %d",&a,&b);

if (a==0.0 && b==0)

{

Page 16: 2012 Ds 03

break;

}

insert_node(&list1, a, b);

}

printf("다항식1 : ");

print(&list1); //다항식1 출력

printf("\n");

//다항식2을 입력받는 부분

printf("다항식2의 항(계수,지수)을 입력하세요. (0 0 이면 입력종료)\n");

while (1)

{

scanf("%f %d",&a,&b);

if (a==0.0 && b==0)

{

break;

}

insert_node(&list2, a, b);

}

printf("다항식2 : ");

print(&list2); //다항식2 출력

printf("\n");

// 다항식3 = 다항식1 + 다항식2

poly_add(&list1, &list2, &list3);

printf("결과 : ");

print(&list3); //다항식3 출력

}

Page 17: 2012 Ds 03

7)최종소스#include <stdio.h>

#include <stdlib.h>

// 연결리스트 노드의 구조

typedef struct listnode

{

double coef;

int expon;

struct listnode *link;

} listnode;

// 연결리스트의 헤더

typedef struct listheader

{

int length;

listnode *head;

listnode *tail;

} listheader;

//초기화 함수

int reset(listheader *plist)

{

plist->length=0;

plist->head=plist->tail=NULL;

return 0;

}

//plist는 연결 리스트의 헤더를 가르키는 포인터

//expon는 지수 coef는 계수

int poly_make(listheader *plist,double coef,int expon)

{

listnode *n=(listnode*)malloc(sizeof(listnode));

n->coef=coef;

n->expon=expon;

Page 18: 2012 Ds 03

n->link=NULL;

if(plist->tail==NULL)

{

plist->head=plist->tail=n;

}

else

{

plist->tail->link=n;

plist->tail=n;

}

plist->length++;

return 0;

}

//list3 = list1 + list2

int poly_add(listheader *plist1,listheader *plist2, listheader *plist3)

{

double sum;

listnode *a=plist1->head;

listnode *b=plist2->head;

while(a,b)

{

if(a->expon == b->expon)

{

sum=a->coef+b->coef;

if(sum!=0)

{

poly_make(plist3, sum, a->expon);

a=a->link;

b=b->link;

}

}

else if(a->expon > b->expon)

{

poly_make(plist3, a->coef, a->expon);

a=a->link;

}

else

{

poly_make(plist3, b->coef, b->expon);

Page 19: 2012 Ds 03

b=b->link;

}

}

return 0;

}

//출력 하기 위한 함수

int poly_print(listheader *plist)

{

listnode *p = plist->head;

for(1; p; p = p->link)

{

printf("%.1fX^%d", p->coef, p->expon);

if(p->link!=NULL)

{

printf(" + ");

}

}

printf("\n");

return 0;

}

//메모리 해제 함수

int poly_delete(listheader *plist)

{

listnode *n=plist->head;

listnode *del;

while(n->link!=NULL)

{

del=n;

n=del->link;

plist->head=n;

free(del);

}

free(n);

return 0;

}

//메인 함수

int main()

Page 20: 2012 Ds 03

{

listheader list1, list2, list3; //리스트 변수 선언

// 연결 리스트이 초기화

reset(&list1);

reset(&list2);

reset(&list3);

// P(X)를 생성

poly_make(&list1, -3.7, 3);

poly_make(&list1, 2.5, 2);

poly_make(&list1, 1, 1);

// S(X)를 생성

poly_make(&list2, 8.2, 3);

poly_make(&list2, -3.1, 2);

poly_make(&list2, 10.2, 1);

// T(X)를 생성

// T(X)=P(X)+S(X)

poly_add(&list1, &list2, &list3);

printf("P(X)의 다항식 : ");

poly_print(&list1);

printf("S(X)의 다항식 : ");

poly_print(&list2);

printf("T(X)의 다항식 : ");

poly_print(&list3);

// 할당한 메모리의 리스트를 해제

poly_delete(&list1);

poly_delete(&list2);

poly_delete(&list3);

return 0;

}

Page 21: 2012 Ds 03

•실행 화면

8)시간복잡도/공간복잡도