문제

이것은 내가 필요한 일을하기에 충분하다는 것을 알고 있기 때문에 이것은 정확히 기술적 인 질문이 아닙니다. '질문을하기 위해.

상황은 : 현재 고급 알고리즘 과정을 수강하고 있으며, '프로그래머로 성장'을 위해서는 실제 과제를 구현하기 위해 Pure C를 사용해야합니다 (실제로는 잘 작동합니다. 실제로는 실제로 힘을내는 거의 모든 실수입니다. 당신은 그것을 고치기 위해 당신이하고있는 일을 완전히 이해합니다). 구현 과정에서, 나는 처음부터 '기본'데이터 구조를 구현 해야하는 문제에 대해 분명히 링크 된 목록뿐만 아니라 스택, 트리 등을 구현해야합니다.

나는이 주제의 목록에 초점을 맞추고 있습니다. 일반적으로 프로그램에서 많은 구조를 사용하여 '메인'구조 또는 다른 더 큰 것 (예 : 해결하는 해시 트리)의 '도우미'구조로서 많은 구조이기 때문입니다. 링크 된 목록을 사용하여 충돌).

이를 위해서는이 목록은 다양한 유형의 요소를 저장해야합니다. 나는 여기서 모든 유형의 목록을 다시 코딩하고 싶지 않다는 전제로 여기에 있다고 가정합니다. 그래서 나는 다음과 같은 대안을 생각해릴 수 있습니다.

  • 공허 포인터 목록 만들기 (kinda ineLegant; 디버그하기가 더 어렵다)
  • 하나의 목록 만 만들지만 a 노동 조합 프로그램에 사용하는 모든 요소 유형을 포함하는 '요소 유형'으로서 (디버그하기 쉽고, 요소가 모두 같은 크기가 아닌 경우 공간을 폐기합니다)
  • 전처리 매크로를 사용하여 모든 유형의 코드를 재생 sglib, 'C ++의 모방'의 STL (창의적 솔루션; 공간을 낭비하지 않으며 요소는 실제로 반환 될 때 명시 적 유형을 가지고 있습니다. 목록 코드의 변경은 정말 극적 일 수 있습니다)
  • 당신의 아이디어/솔루션

질문을 명확하게하기 위해 : 위의 것이 가장 좋은 것은 무엇입니까?

추신 : 기본적으로 학문적 맥락에 있기 때문에 업계에서 Pure C와 함께 일하는 사람들의 견해에도 관심이 있습니다. 나는 대부분의 순수한 C 프로그래머가 임베디드 장치 영역에 있다는 것을 이해합니다. 여기서 내가 직면하고있는 이런 종류의 문제가 일반적이라고 생각하지 않습니다. 그러나 거기에있는 사람이 '현실 세계'에서 어떻게 행해 졌는지 알고 있다면, 나는 당신의 의견에 매우 관심이있을 것입니다.

도움이 되었습니까?

해결책

void * 목록 자체에 별도로 할당을 관리해야하므로 링크 된 목록에 약간의 고통이 있습니다. 내가 과거에 사용한 한 가지 접근법은 다음과 같은 '가변 크기'구조를 갖는 것입니다.

typedef struct _tNode {
    struct _tNode *prev;
    struct _tNode *next;
    int payloadType;
    char payload[1];  // or use different type for alignment.
} tNode;

이제 나는 그것이 그렇지 않다는 것을 알고 있습니다 바라보다 가변 크기이지만 따라서 구조를 할당합시다.

typedef struct {
    char Name[30];
    char Addr[50];
} tPerson;
tNode *node = malloc (sizeof (tNode) - 1 + sizeof (tPerson));

이제 모든 의도와 목적을 위해 다음과 같이 보이는 노드가 있습니다.

typedef struct _tNode {
    struct _tNode *prev;
    struct _tNode *next;
    int payloadType;
    char Name[30];
    char Addr[50];
} tNode;

또는 그래픽 형태 (여기서 [n] 수단 n 바이트) :

+----------------+
|    prev[4]     |
+----------------+
|    next[4]     |
+----------------+
| payloadType[4] |                
+----------------+                +----------+
|   payload[1]   | <- overlap ->  | Name[30] |
+----------------+                +----------+
                                  | Addr[50] |
                                  +----------+

즉, 페이로드를 올바르게 해결하는 방법을 알고 있다고 가정합니다. 다음과 같이 수행 할 수 있습니다.

node->prev = NULL;
node->next = NULL;
node->payloadType = PLTYP_PERSON;
tPerson *person = &(node->payload); // cast for easy changes to payload.
strcpy (person->Name, "Bob Smith");
strcpy (person->Addr, "7 Station St");

그 캐스트 라인은 단순히 주소를 캐스팅합니다 payload 캐릭터 (에서 tNode 유형)는 실제 주소입니다 tPerson 페이로드 유형.

이 방법을 사용하면 노드에서 원하는 페이로드 유형을 전달할 수 있습니다. 각 노드의 다른 페이로드 유형, 연합의 낭비 된 공간없이. 이 낭비는 다음과 같이 볼 수 있습니다.

union {
    int x;
    char y[100];
} u;

여기서 목록에 정수 유형을 저장할 때마다 96 바이트가 낭비됩니다 (4 바이트 정수의 경우).

페이로드 유형 tNode 이 노드가 전달하는 유형의 페이로드를 쉽게 감지 할 수 있으므로 코드가 처리 방법을 결정할 수 있습니다. 라인을 따라 무언가를 사용할 수 있습니다.

#define PAYLOAD_UNKNOWN     0
#define PAYLOAD_MANAGER     1
#define PAYLOAD_EMPLOYEE    2
#define PAYLOAD_CONTRACTOR  3

또는 (아마도 더 나은) :

typedef enum {
    PAYLOAD_UNKNOWN,
    PAYLOAD_MANAGER,
    PAYLOAD_EMPLOYEE,
    PAYLOAD_CONTRACTOR
} tPayLoad;

다른 팁

내 $ .002 :

  • 공허 포인터 목록 만들기 (친절한, 디버그가 더 어려워)

C로 작성 해야하는 경우 IMHO는 그렇게 나쁜 선택이 아닙니다. I IMHO는 API 메소드를 추가하여 애플리케이션이 디버깅의 용이성을 위해 print () 메소드를 제공 할 수 있도록 할 수 있습니다. (예 :) 항목이 목록에 추가되거나 제거되면 유사한 방법을 호출 할 수 있습니다. (링크 된 목록의 경우, 이것은 일반적으로 필요하지 않지만 더 복잡한 데이터 구조 (예 : 해시 테이블)의 경우 때로는 생명을 구할 수 있습니다.)

  • 단 하나의 목록 만 만들지만 Union을 '요소 유형'으로 사용하고 프로그램에 사용할 모든 요소 유형이 포함되어 있습니다 (디버그하기 쉽고 요소가 모두 같은 크기가 아닌 경우 공간을 폐기합니다).

나는 전염병처럼 이것을 피할 것입니다. (글쎄, 당신은 물었습니다.) 데이터 구조에서 포함 된 유형으로 수동으로 구성되고 컴파일 시간 종속성을 갖는 것은 모든 세계에서 최악입니다. 다시, IMHO.

  • 사전 프로세서 매크로를 사용하여 sglib (sglib.sourceforge.net)의 스타일로 모든 유형의 코드를 재생성하여 'C ++'의 STL (창의적 솔루션; 낭비하지 않음; 요소는 실제로 명시 적 유형을 가지고 있습니다. 반환됩니다. 목록 코드의 변경 사항은 정말 극적 일 수 있습니다)

흥미로운 아이디어이지만 Sglib를 모르기 때문에 그 이상을 말할 수는 없습니다.

  • 당신의 아이디어/솔루션

나는 첫 번째 선택과 함께 갈 것입니다.

과거에 우리 코드 (이후 C ++로 변환) 에서이 작업을 수행했으며 당시에는 공허* 접근법을 결정했습니다. 방금 유연성을 위해이 작업을 수행했습니다. 우리는 거의 항상 목록에 포인터를 저장하고 있었고 솔루션의 단순성이 있었고, 그 방법의 유용성은 다른 접근 방식에 대한 단점보다 더 중요했습니다.

즉, 디버깅하기 어려운 불쾌한 버그를 일으킨 한 번이 있었기 때문에 완벽한 솔루션이 아닙니다. 그래도 지금 다시이 일을하고 있다면 여전히 내가 취한 사람이라고 생각합니다.

전처리 매크로를 사용하는 것이 가장 좋습니다. 그만큼 Linux 커널 링크 목록 C에서 원형으로 연결된 목록의 우수한 eficient 구현입니다. 매우 휴대가 많고 사용하기 쉽습니다. 여기 Linux 커널 2.6.29 List.h 헤더의 독립형 버전.

freebsd/openbsd SYS/대기열 일반 매크로 기반 링크 목록에 대한 또 다른 좋은 옵션입니다.

나는 몇 년 동안 C를 코딩하지 않았지만 말 잘하는 "문자열 및 공통 데이터 구조에 대한 대규모 유틸리티 기능 세트"를 제공한다고 주장하며 그중에 연결된 목록입니다.

다른 언어의 기술을 사용하여 이런 종류의 문제를 해결하는 것이 유혹적이지만, 제네릭은 실제로는 거의 승리가 아닙니다. 아마도 대부분의 시간을 제대로 얻는 통조림 솔루션이있을 것입니다 (그리고 그들이 잘못 될 때 문서에 알려주십시오), 과제의 요점을 놓칠 수 있으므로 두 번 생각할 것입니다. 몇 가지 경우가 많을 때, 자신의 것을 굴릴 수는 있지만 합리적인 규모의 프로젝트의 경우 디버깅 노력의 가치가 없을 것입니다.

오히려 언어 X로 프로그래밍 할 때 언어 x의 관용구를 사용해야합니다. 파이썬을 사용할 때는 Java를 쓰지 마십시오. 체계를 사용할 때 C를 쓰지 마십시오. C99를 사용할 때는 C ++를 쓰지 마십시오.

나 자신은 아마도 Pax의 제안과 같은 것을 사용하게 될 것입니다. 그러나 실제로 공통 사례를 편리하게 만들기 위해 Char [1] 및 void* 및 int의 결합을 사용합니다.

(아마도 Fibonacci 트리를 구현하게 될 것입니다. 단지 깔끔하게 들리는 것을 원인으로, RB 트리가 맛을 잃기 전에 여러 번만 구현할 수 있습니다. .))

편집하다: 귀하의 의견을 바탕으로 통조림 솔루션을 사용하는 데 꽤 좋은 사례가있는 것 같습니다. 강사가 허용하고 제공하는 구문이 편안하다고 느끼면 소용돌이를주십시오.

이것은 좋은 문제입니다. 내가 좋아하는 두 가지 솔루션이 있습니다.

  • 데이브 핸슨 C 인터페이스 및 구현 목록을 사용합니다 void * 나에게 충분한 포인터.

  • 나를 위해 재학생, 나는 썼다 유형 별 목록 기능을 생성하는 AWK 스크립트. 전처리 매크로와 비교할 때 추가 빌드 단계가 필요하지만 시스템의 작동은 많은 경험이없는 프로그래머에게 훨씬 투명합니다. 그리고 그것은 나중에 커리큘럼에서 볼 수있는 파라 메트릭 다형성의 사례를 만드는 데 실제로 도움이됩니다.

    한 기능 세트는 다음과 같습니다.

    int      lengthEL (Explist *l);
    Exp*     nthEL    (Explist *l, unsigned n);
    Explist *mkEL     (Exp *hd, Explist *tl);
    

    AWK 스크립트는 150 라인 공포입니다. C 코드를 검색합니다 typedefS 및 각각의 목록 함수 세트를 생성합니다. 아주 오래되었습니다. 나는 아마 지금 더 잘할 수있을 것이다 :-)

나는 노조 목록에 시간 (또는 하드 드라이브의 공간)을주지 않을 것입니다. 안전하지 않고 확장 할 수 없으므로 사용할 수도 있습니다. void * 그리고 그것으로 끝났습니다.

무효* 목록으로 만드는 것보다 한 가지 개선은 공허*를 포함하는 스트러크 목록과 유형, 크기 등을 포함하여 공허*가 가리키는 것에 대한 메타 데이터의 목록으로 만드는 것입니다.

기타 아이디어 : Perl 또는 LISP 통역사를 포함합니다.

또는 반쯤 가십시오 : Perl 라이브러리와 연결하여 Perl SV 또는 무언가 목록으로 만드십시오.

나는 아마도 빈 공간* 접근 방식을 직접 갈 것입니다. 그러나 데이터를 XML로 저장할 수있었습니다. 그런 다음 목록에는 데이터에 대한 숯이있을 수 있습니다 (필요한 하위 요소에 대해 주문형 구문 분석) ....

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top