2010-02-12 2 views
3

Я просто хочу просто объяснить процесс связывания при нажатии данных в стек. Я знаю, как использовать код из моей книги, но я не совсем уверен, что понимаю, как работает этот процесс, когда вы перемещаете ссылку заголовка стека с одного на другой.Объяснение того, как работают стеки в C

Для стеков, как:

typedef struct node 
{ 
    void dataptr; 
    struct node* link; 
}STRUCT_NODE; 

typedef struct 
{ 
    int count; 
    STACK_NODE* top; 
}STACK; 

Как изменить ссылку, чтобы указать новые данные в стек. Кроме того, я не знаю,

+0

Можете ли вы разместить код? –

+0

Для таких стеков: 'typedef struct node { void dataptr; struct node * link; } STRUCT_NODE typedef struct { int count; STACK_NODE * сверху; } STACK; ' Как изменить ссылку, чтобы указать на новые данные, наложенные на стек. Также я не знаю – shinjuo

+0

Также не знаю, как поместить вещи в код? Может кто-то сказать мне, как это сделать. Извините, что я очень новичок на этом сайте – shinjuo

ответ

7

Стеки могут быть реализованы различными способами, но учитывая то, как вы фразу ваш вопрос я предполагаю, что ваш стек просто связанный список, что-то вроде

head 
↓ 
A → B → C → D → 0 

«при перемещении ссылка стека головки от одного к другому»картина просто меняется:

head 
    ↓ 
A → B → C → D → 0 

конечно, не достижим больше на этом графике, так что лучше иметь другой указатель на него где-то (будь то только избавиться от него), но суть в том, как складывается стек (на m aking head = head->next, если каждый узел в стеке является struct node с полем next, который является struct node*, и, конечно же, head является также struct node*).

Это для того, чтобы вытащить что-то из стека (и вы должны освободить память, используемую в этом случае A). В подробных шагах он будет:

1/Сохранение старой головы.

 head 
     ↓ 
old → A → B → C → D → 0 

2/Регулировка головы.

  head 
      ↓ 
old → A → B → C → D → 0 

3/Возвращение старого голову (на который указывает old).

Если вместо этого вы говорите что-то толкает на стек, это операция, которая включает в себя:

1/Создание нового элемента.

head 
    ↓ 
Z A → B → C → D → 0 

2/Указав его к текущей голове

head 
    ↓ 
Z → A → B → C → D → 0 

3/Регулировка головой, чтобы указать на него.

head 
↓ 
Z → A → B → C → D → 0 
+0

@Alex, +1 для диаграмм, я всегда их люблю. Но я думал, что у вас неправильная операция (поп, а не толчок), поэтому я надеюсь, что вы не против, что я немного ее расширил. Не стесняйтесь очищать мой беспорядок, если хотите. – paxdiablo

+0

@Alex, диаграммы слишком хороши. Кстати, как вы их создаете? – Jay

+0

@Jay, я просто набрал их - стрелки доступны (они являются символами Юникода), например. в диалоговом окне «Палитра символов» на Mac. –

0

Скажите, что у вас есть STACK с именем my_stack и STACK_NODE с именем my_node.Чтобы добавить my_node к my_stack, сделайте следующее:

my_node.link = my_stack.top; 
my_stack.top = &my_node; 
my_stack.count = my_stack.count + 1; 
1

Учитывая ваши структуры данных, представляющие узел в стеке, и собственно сам стек:

typedef struct node { 
    void  *dataptr; 
    struct node *link; 
} NODE; 

typedef struct { 
    int count; 
    NODE *top; 
} STACK; 

вы бы инициализировать стек следующим образом:

STACK myStack; 
myStack.count = 0; 
myStack.top = NULL; 

Это в основном дает пустой стек. Я собираюсь использовать top, чтобы решить, пуст ли пуст - вы можете использовать либо count, либо top (как 0 или NULL соответственно), чтобы выполнить эту работу, но это хорошая идея, чтобы выбрать ее и придерживаться ее в случае, если вы когда-либо писали некоторые ошибки кода в будущем, где кэшируется подсчет и фактический отсчет выйти из шага :-)

протолкнуть узел в стек, это простая операция:

  • выделить новый узел и установить полезная нагрузка (1).
  • укажите ссылку нового узла на текущую головку.
  • направьте головку на новый узел (3).
  • увеличить счетчик (4).

Следующий код показывает, как вы можете это сделать:

/* 1 */ NODE *newNode = malloc (sizeof (NODE)); // should check for failure. 
     newNode->dataptr = NULL; 
/* 2 */ newNode->link = myStack.top; 
/* 3 */ myStack.top = newNode; 
/* 4 */ myStack.count++; 

Это будет толкать на любой пустой стек или населенной один. Краевой случай пустого стека увидит, что newNode.link установлен на NULL, затем myStack.top установлен на newNode, что является правильным поведением.

Чтобы выскочить узел из стека:

  • сохранить нынешний глава (1).
  • Если текущая головка не равна NULL, продвиньте головку к ее ссылке (и уменьшите счет).
  • вернуть сохраненную текущую головку (3).

, что в переводе с кодом, является:

/* 1 */ NODE *popNode = myStack.top; 
/* 2 */ if (myStack.top != NULL) { 
      myStack.top = myStack.top->link; 
      myStack.count--; 
     } 
/* 3 */ return popNode; 

Это возвращает либо адрес хлопнутого узла или NULL, если стек был пуст.

Весь набор операций может быть инкапсулирован следующим образом. Надеемся, что комментарии сделают это самоочевидным в сочетании с комментариями выше, но не стесняйтесь поднимать любые проблемы, и я буду обращаться к ним с помощью редактирования.


// Error codes (probably should be enums). 

#define STACK_ERR_OKAY  0 
#define STACK_ERR_NOTEMPTY 1 
#define STACK_ERR_NOPAYLOAD 2 
#define STACK_ERR_NOMEMORY 3 

// Structures. 

typedef struct sNode { 
    void   *data; // Payload pointer. 
    struct sNode *next; // Link to next node. 
} tNode; 

typedef struct { 
    int   count; // Count for fast sizing. 
    NODE   *top; // First node. 
} tStack; 

// Make a new stack returning its pointer or NULL on failure. 

tStack *stackNew (void) { 
    tStack stack = malloc (sizeof (tStack)); 
    if (stack != NULL) { 
     stack->count = 0; 
     stack->top = NULL; 
    } 
    return stack; 
} 

// Delete a current stack, must be empty first. 

int stackDel (tStack *stack) { 
    if (stack->top != NULL) 
     return STACK_ERR_NOT_EMPTY; 
    free (stack); 
    return STACK_ERR_OK; 
} 

// Push a pointer payload (no NULLs allowed) onto the stack. 

int stackPush (tStack *stack, void *payload) { 
    if (payload == NULL) 
     return STACK_ERR_NOPAYLOAD; 
    tNode *node = malloc (sizeof (tNode)); 
    if (node == NULL) 
     return STACK_ERR_NOMEMORY; 
    node->data = payload; 
    node->next = stack->top; 
    stack->top = node; 
    stack->count++; 
    return STACK_ERR_OK; 
} 

// Pop a pointer payload from the stack. Returns NULL if stack was empty. 

int stackPop (tStack *stack) { 
    tNode *node = stack->top; 
    if (node == NULL) { 
     return NULL; 
    stack->top = node->next; 
    stack->count--; 
    return node->data; 
} 

// Get stack size. 

int stackSize (tStack *stack) { 
    return stack->count; 
} 

Причина я настаивал на том, что стек должен быть пуст перед удалением потому, что код не знает точно, что полезная нагрузка.Это может быть простым указатель на блок памяти (мелкий), в этом случае вы могли бы просто использовать:

void stackDel (tStack *stack) { 
    tNode *node = stackPop (stack); 
    while (node != NULL) { 
     free (node); 
     node = stackPop (stack); 
    } 
    free (stack); 
} 

, но, если это указатель на память держит другие указатели на память, это более проблематично автоматически освободить (это, вероятно, лучше всего сделать в качестве обратного вызова вызывающему API, поскольку это будет единственный зверь, который точно знал, как правильно освободить память). Намного проще сделать это предварительным условием для вызывающего абонента.

Смежные вопросы