/큐

2013-05-13 3 views
3
나는이 그러나 아직 내가 (사실 난 그냥 설명은 간단 매우 복잡) 다음과 같은 데이터 구조체가 성공하지 해결하기 위해 열심히 노력하고있다

:/큐

typedef struct node{ 
struct node* next; 
    void* arg; 
}node_t; 

typedef struct queue{ 
node_t* head; 
node_t* tail; 
}queue_t; 

addQ(queue_t*ptr , int data) 
{ 
    queue_t* q = ptr; 
    node_t * n = malloc(sizeof(*n)); 

    n->arg = data; 
    n->next = NULL; 

    if(NULL == q->head){ 
     q->head = q->tail = n; 
     return ; 
    } 
    q->tail->next = n; 
    q->tail = q->tail->next; 
} 

addQ(q, 12); 
addQ(q, 12); 
addQ(q, 4); 
addQ(q, 12); 
addQ(q, 12); 
addQ(q, 14); 
addQ(q, 12); 
addQ(q, 12); 

내가 값 12

모든 노드를 삭제하려면 :

지금 나는 (I 그러나 아직 성공하지 몇 가지 방법을 시도), 그냥 참조를 위해이 순서를 고려 같은 값의 노드를 삭제할

+0

항상 한 두 가지 방법을 보여주는 데 도움이됩니다. – Dukeling

+0

그냥 간단한 쿼리는 대기열 또는 에너럴 링크 된 목록입니까?, 그것의 대기열 솔직히 당신도 당신이 선택한 어떤 노드를 삭제하려고해서는 안됩니다, dequeue 내가 사용하고 있어야합니다 옵션입니다, 어떤 방법입니다 연결된 목록? –

+0

@duke, 물론 내 버전을 게시 할 수 있지만 아직 작동하지 않습니다. –

답변

0

이미 큐의 다음 항목을 가져 와서 제거하는 함수가 있다고 가정하면이 함수를 getQ(q)으로 호출하면 이미 가지고있는 작업을 사용하여 큐의 내부를 알지 않고도 목표를 달성 할 수 있습니다 , 예. 그것은 '아무튼, 그것은처럼 여전히

node_t *n; 
queue_t *q2 = initialiseQ(); 
while (n = getQ(q)) { 
    if (n->arg != 12) { 
     addQ(q2,n); 
    } 
} 
free(q); 
q = q2; 
+0

그래, 내가 머리에서 제거하고 대기열에 추가 할 수있는 기능을 가지고뿐만 아니라 대기열에서 큐 수 있습니다, 당신은 다른 대기열을 제안하고 있습니까? 당신이 수십만 건의 작업을 기대할 때 비싸지 않습니까 ?? –

+0

포인터를 움직이는 것은별로 큰 문제가 아닙니다. 노드를 완전히 재 할당 한 다음 이전 노드를 할당 해제하는 경우 매우 위험합니다. 어쨌든 모든 노드의 포인터를 횡단하고 있기 때문에 포인터를 바꿀 수는 없습니다. 그러나 그것은 인라인으로 할 수 있습니다. – xaxxon

+0

@ xaxxon의 포인트와 Select Call의 포인트가 모두 정확하다고 생각합니다. 현재의'addQ()'구현은 매번 노드를 할당하는데, 수십만 번 수행 되었다면 문제가 될 수 있습니다. 그러나 기존의'node'를 매개 변수로 사용하고 (xaxxon에 의해 제안 된 것처럼) 포인터를 주변으로 이동시킨'addQ()'의 대안 구현은 쓰기 쉽습니다 (현재'addQ()'는 그런 다음 새로운 addQ_node()를 매개 변수로 새 노드를 호출하고 실행하는 것이 매우 빠릅니다. – Simon

4

이 솔루션은 이중 포인터와 약간의 털이 있어요,하지만 난 : 같은 (argvoid 때문에이 작동하지 않습니다,하지만 논리는 명확해야한다) 어떤 노드 (첫 번째 노드와 나머지 노드)가 검사되는지 특별한 경우가 있습니다. 나는 무슨 일이 벌어지고 있는지를 설명하기 위해 충분한 설명을 덧붙이려고했지만, 언뜻보기에는 나를 따라 가기가 여전히 어렵다.

의사 ..

Queue * q; 
VALUE = 12; 

// double pointer so we can treat the queue head and subsequent nodes the same. 
// because they are both pointers to Node. 
// Otherwise you'd have to have code that says if the one you're removing is the 
// first element of the queue, adjust q->head, otherwise adjust node->next. 
// This lets you not special case the deletion. 
Node ** node_ptr = &(q->head) 

while (*node_ptr != null) { 
    if ((**node_ptr).arg == VALUE) { 
     // store off the matching node to be freed because otherwise we'd orphan 
     // it when we move the thing pointing to it and we'd never be able to free it 
     Node * matched_node = *node_ptr; 

     // when we find a match, don't move where node_ptr points, just change the value it 
     // points to to skip the matched node and point to the one after it (or null) 
     *node_ptr = matched_node->next; 
     free(matched_node); 
    } else { 
     // otherwise, nothing was deleted, so skip over that node to the next one. 
     // remember, **node_ptr is a double dereference, so we're at the node 
     // now, so then we grab the address of the non-matching node's next value so it can be 
     // potentially changed in the next iteration 
     node_ptr = &((**node_ptr).next); 
    } 
} 
+2

+1 처음 나타나는 것보다 훨씬 깨끗합니다. 이것은 본질적으로리스트를 스캔하고, node_ptr에서 잠재적 인 노드 매치를 참조 할 수있는 포인터의 주소 *를 유지한다. 성냥에, 그 마디는 연결이 끊기고 구멍은 첫째로 그것을 참조한 포인터에서 그것의 "다음"저장해서 채워진다. 유일하게 잠재적 인 문제는 테일 픽업 (tail-fixup)이지만, 아이디어는 분명해야하며, 노드의 복제가 전혀 필요없는 매우 효율적인 메모리입니다. – WhozCraig

+0

아직 청소하고 있습니다. 참으로, 많은 포인터 자료는 내가 오랫동안 그것을 해왔음에도 불구하고 루프를 위해 돌아서도록 만든다. – xaxxon

+0

이것은 내가 생각하고 있었던 것, 세부 설명을위한 감사합니다 :) –

0

여기에 이중 포인터를 사용하지 않는 인라인 솔루션입니다. 큐 구조에서 노드 구조로의 변경을 조정하기위한 포인터 이후 첫 번째 요소와 후속 요소를 다르게 처리해야합니다.

또한 후속 노드의 경우 후미 노드를 추적해야합니다. 일치 노드를 삭제할 때 조정해야하기 때문입니다.

Queue * q; 
VALUE = 12; 


// handle the case where the first node matches. 
// you have to adjust the q's head pointer 
// delete from the head and set a new head node until a non-matching head is found 
while (q->head != NULL && q->head->arg == VALUE) { 
    Node * matching_node = q->head; 
    q->head = q->head->next; 
    free(matching_node); 
} 

// if there is more than one node left, need to check the subsequent nodes 
if (q->head != NULL && q->head->next != NULL) { 

    Node * node_ptr = q->head->next; 
    Node * prev_node_ptr = q->head; 

    while (node_ptr != NULL) { 
     if (node_ptr->arg == VALUE) { 
      Node * matched_node = node_ptr; // don't orphan it before it's freed 

      // You don't move the prev_node pointer since that doesn't change when a match 
      // is found. Only the node_ptr, which skips to the next one. 
      node_ptr = node_ptr->next; 
      free(matched_node);    
     } else { 
      prev_node_ptr = node_ptr; 
      node_ptr = node_ptr->next; 
     } 
    } 
} 
+0

아 다시 한번 감사드립니다. 물건을 조이는 곳을 찾았습니다 :) –

+0

체크 표시를 제거하는 것에 대한 대답으로 문제가 있었습니까? – xaxxon

+0

그냥 내 버전이 더 많은 버그를 가지고있는 것처럼 보이지만, 다른 버전은 정상적으로 작동합니다. –