數據結構-順序棧和鏈式棧的實現

棧是一種特殊的線性表,它特殊在對線性表的操作進行了限制,只能在它的一端進行插入和刪除,如下圖所示:
這裏寫圖片描述
遵循的是“先進後出”(first in last out)的規則,簡稱爲”FILO”。
既然棧也是線性表,那麼線性表的存儲結構同樣也適用於棧,通常有順序棧和鏈式棧兩種。
1.順序棧的實現
頭文件聲明:

seqstack.h
#pragma once

#include<stddef.h>

typedef char SeqStackType;

typedef struct SeqStack
{
    SeqStackType* data;
    size_t size;
    size_t capacity;//data這段內存中能容納的元素個數
}SeqStack;

void SeqStackInit(SeqStack* stack);//初始化

void SeqStackDestroy(SeqStack* stack);//銷燬

void SeqStackReSize(SeqStack* stack);//重新設置大小

void SeqStackPush(SeqStack* stack,SeqStackType value);//壓棧

void SeqStackPop(SeqStack* stack);//出棧

//返回兩個信息:執行成功失敗,棧頂元素是多少
int SeqStackTop(SeqStack* stack,SeqStackType* value);//取棧頂元素,value輸出型參數

具體實現及測試代碼:

seqstack.c
#include"seqstack.h"
#include<stdio.h>
#include<stdlib.h>
void SeqStackInit(SeqStack* stack)
{
    stack->size = 0;
    stack->capacity = 1000;
    stack->data = (SeqStackType*)malloc(stack->capacity*sizeof(SeqStackType));//開闢空間
}

void SeqStackDestroy(SeqStack* stack)
{
    free(stack->data);//釋放數據
    stack->size = 0;//大小設爲空
    stack->capacity = 0;
}

void SeqStackReSize(SeqStack* stack)
{
    if(stack->size < stack->capacity)//棧大小小於最大容量,不需要擴容,直接返回
    {
        return;
    }
    stack->capacity = stack->capacity*2+1;//擴容規則根據需求選擇
    SeqStackType* new_ptr = (SeqStackType*)malloc(stack->capacity * sizeof(SeqStackType));//重新開闢空間
    int i = 0;
    for( ;i < stack->size;i++)
    {
        new_ptr[i] = stack->data[i];//將以前棧的數據賦給新開闢的空間
    }
    free(stack->data);//釋放以前的棧數據
    stack->data = new_ptr;//更新指針
    return;
}
void SeqStackPush(SeqStack* stack,SeqStackType value)
{
    if(stack == NULL)
    {
        return;   //非法輸入
    }
    if(stack->size >= stack->capacity)//當棧大小大於棧的最大容量時,擴容
    {
        //TODO 擴容
        SeqStackReSize(stack);
    }
    stack->data[stack->size++] = value;
}

void SeqStackPop(SeqStack* stack)
{
    if(stack == NULL)
    {
        return; //非法輸入
    }
    if(stack->size == 0)
    {
        return;  //空棧
    }
    --stack->size;
    return;
}

int SeqStackTop(SeqStack* stack,SeqStackType* value)
{
    if(stack == NULL)
    {
        return 0; //非法輸入
    }
    if(stack->size == 0)
    {
        return 0; //空棧
    }
    *value = stack->data[stack->size-1];
    return 1;
}
//////////////////////////////////////////////
///////////////以下爲測試代碼////////////////
////////////////////////////////////////////
#include<stdio.h>
#define TEST_HEADER printf("\n======================%s========================\n",__FUNCTION__)
void SeqStackPrintChar(SeqStack*stack,char* msg)
{
    if(stack == NULL)
    {
        return;  //非法輸入
    }
    printf("[%s]\n",msg);
    int i = 0;
    for( ;i <stack->size;i++)
    {
        printf("[%c] ",stack->data[i]);
    }
    return;
}
void TestInit()
{
     TEST_HEADER;
     SeqStack stack;
     SeqStackInit(&stack);
     printf("size expected 0,actual %lu\n",stack.size);
     printf("capacity expected 1000;actual %lu\n",stack.capacity);
}
void TestDestroy()
{

     TEST_HEADER;
     SeqStack stack;
     SeqStackInit(&stack);
     SeqStackDestroy(&stack);
}

void TestPush()
{
     TEST_HEADER;
     SeqStack stack;
     SeqStackInit(&stack);
     SeqStackPush(&stack,'a');
     SeqStackPush(&stack,'b');
     SeqStackPush(&stack,'c');
     SeqStackPush(&stack,'d');
     SeqStackPrintChar(&stack,"入棧四個元素");
}

void TestPop()
{
     TEST_HEADER;
     SeqStack stack;
     SeqStackInit(&stack);
     SeqStackPush(&stack,'a');
     SeqStackPush(&stack,'b');
     SeqStackPush(&stack,'c');
     SeqStackPush(&stack,'d');
     SeqStackPop(&stack);
     SeqStackPrintChar(&stack,"出棧棧頂元素");
}

void TestTop()
{

     TEST_HEADER;
     SeqStack stack;
     SeqStackInit(&stack);
     SeqStackPush(&stack,'a');
     SeqStackPush(&stack,'b');
     SeqStackPush(&stack,'c');
     SeqStackPush(&stack,'d');

     SeqStackType value;
     int ret = SeqStackTop(&stack,&value);
     printf("ret expected 1,actual %d\n",ret);
     printf("value expected d,actual %c\n",value);

     SeqStackPop(&stack);
     SeqStackPop(&stack);
     ret = SeqStackTop(&stack,&value);
     printf("ret expected 1,actual %d\n",ret);
     printf("value expected b,actual %c\n",value);

     SeqStackPop(&stack);
     SeqStackPop(&stack);
     ret = SeqStackTop(&stack,&value);
     printf("ret expected 0,actual %d\n",ret);
}
int main()
{
    TestInit();
    TestDestroy();
    TestPush();
    TestPop();
    TestTop();
    printf("\n");
    return 0;
}

上面這種棧的實現採用了擴容的方式,避免了棧溢出問題。
順序棧是用數組的形式存儲數據,數組中的元素在內存中是連續存儲的,這樣在訪問數據時,時間複雜度較小,效率高,插入和刪除時不需要移動元素。但是系統將內存分配給數組後,這些內存其他任務不可用,內存利用率低。
2.鏈式棧的實現
鏈式棧是用指針來指示數據的存儲位置的,元素在內存中可以隨意存儲,不需要連續的存儲位置,內存利用率高,一般適用於棧元素數目變化較大或不清楚棧元素的數目的情況,鏈棧存儲如下圖所示:
這裏寫圖片描述
實現:
頭文件聲明:

linkstack.h
#include<stddef.h>

typedef char LinkStackType;
typedef struct LinkStackNode
{
    LinkStackType data;
    struct LinkStackNode* next;
}LinkStackNode;

LinkStackNode* phead;

void LinkStackInit(LinkStackNode** phead);//鏈式棧初始化

void LinkStackPush(LinkStackNode** phead,LinkStackType value);//入棧

void LinkStackPop(LinkStackNode** phead);//出棧

int LinkStackTop(LinkStackNode* phead,LinkStackType* value);//取棧頂元素

具體實現及測試代碼:

linkstack.c
#include"linkstack.h"
#include<stdio.h>
#include<stdlib.h>

LinkStackNode* CreateLinkStackNode(LinkStackType value)//創建結點
{
    LinkStackNode* new_node = (LinkStackNode*)malloc(sizeof(LinkStackNode));//開闢空間
    new_node->data = value;
    new_node->next = NULL;

    return new_node;
}

void LinkStackInit(LinkStackNode** phead)
{
    if(phead == NULL)
    {
        return;
    }
    *phead = NULL;
    return;
}

void LinkStackDestroy(LinkStackNode** phead)
{
    if(phead == NULL)
    {
        return;//非法輸入
    }
    if(*phead == NULL)
    {
        return;//空棧
    }
    LinkStackNode* cur = *phead;
    while(cur != NULL)
    {
        LinkStackNode* to_delete = cur;
        free(to_delete);
        cur = cur->next;
    }
    return;
}

void LinkStackPush(LinkStackNode** phead,LinkStackType value)
{
    if(phead == NULL)
    {
        return;//非法輸入
    }

    LinkStackNode* cur = *phead;
    (*phead) = CreateLinkStackNode(value);//頭結點直接指向新結點,使新結點爲新的頭結點
    (*phead)->next = cur;

    return;
}

void LinkStackPop(LinkStackNode** phead)
{
    if(phead == NULL)
    {
        return; //非法輸入
    }
    if(*phead == NULL)
    {
        return;//空棧
    }
    LinkStackNode* to_delete = *phead;
    (*phead) = to_delete->next;//更新頭結點
    free(to_delete);//釋放舊的頭結點

    return;
}


int LinkStackTop(LinkStackNode* phead,LinkStackType* value)
{
    if(phead == NULL)
    {
        return 0;//非法操作
    }
    *value = (phead)->data;

    return 1;
}

////////////////////////////////////////////////
/////////////以下是測試代碼////////////////////
///////////////////////////////////////////////
#include<stdio.h>
#if 1
#define TEST_HEADER printf("\n===============================%s===================================\n",__FUNCTION__)

void LinkStackPrintChar(LinkStackNode* phead,const char* msg)
{
    printf("[%s]\n",msg);
    if(phead == NULL)
    {
        return;
    }
    LinkStackNode* cur = phead;
    for( ;cur != NULL;cur = cur->next)
    {
        printf("[%c] ",cur->data);
    }
    printf("\n");

}

void TestInit()
{
    TEST_HEADER;
    LinkStackNode* head;
    LinkStackInit(&head);
}

void TestPush()
{

    TEST_HEADER;
    LinkStackNode* head;
    LinkStackInit(&head);

    LinkStackPush(&head,'a');
    LinkStackPush(&head,'b');
    LinkStackPush(&head,'c');
    LinkStackPush(&head,'d');

    LinkStackPrintChar(head,"入棧四個元素");
}

void TestPop()
{

    TEST_HEADER;
    LinkStackNode* head;
    LinkStackInit(&head);

    LinkStackPop(&head);
    LinkStackPrintChar(head,"嘗試對空棧操作");
    LinkStackPush(&head,'a');
    LinkStackPush(&head,'b');
    LinkStackPush(&head,'c');
    LinkStackPush(&head,'d');

    LinkStackPop(&head);
    LinkStackPop(&head);
    LinkStackPrintChar(head,"出棧兩個元素");
    LinkStackPop(&head);
    LinkStackPop(&head);
    LinkStackPrintChar(head,"出棧兩個元素");
}

void TestTop()
{

    TEST_HEADER;
    LinkStackNode* head;
    LinkStackInit(&head);

    LinkStackPush(&head,'a');
    LinkStackPush(&head,'b');
    LinkStackPush(&head,'c');
    LinkStackPush(&head,'d');

    LinkStackType value;
    int ret = LinkStackTop(head,&value);
    printf("ret expected 1.actual %d\n",ret);
    printf("value expected d,actual %c\n",value);

    LinkStackPop(&head);
    LinkStackPop(&head);
    ret = LinkStackTop(head,&value);
    printf("ret expected 1.actual %d\n",ret);
    printf("value expected b,actual %c\n",value);

    LinkStackPop(&head);
    LinkStackPop(&head);
    ret = LinkStackTop(head,&value);
    printf("ret expected 0,actual %d\n",ret);
}

int main()
{
    TestInit();
    TestPush();
    TestPop();
    TestTop();
    printf("\n");

}
#endif

發佈了56 篇原創文章 · 獲贊 13 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章