[C基础]栈、单向链表和队列的简易C实现

C语言比较偏底层,很多常用的数据结构需要自己实现,不像高等语言直接就有现成的类库可使用。

1. 栈定义和实现

下面是一个栈的简易实现,适合新人入门参考。可以方便的对任意数据类型进行压栈出栈操作。

#define MAX_STACK_DEPTH 4096

typedef struct _STACK
{
    void *Array[MAX_STACK_DEPTH];
    int  Depth;
    void (*Push)(struct _STACK *,void *);
    void *(*Pop)(struct _STACK *);
}
STACK;

void StackPush(STACK *Stack, void *Element)
{
    if (Stack->Depth < MAX_STACK_DEPTH)
    {
        Stack->Array[Stack->Depth++] = Element;
    }
}

void *StackPop(STACK *Stack)
{
    if (Stack->Depth <= 0)
    {
        return NULL;
    }

    return Stack->Array[--Stack->Depth];
}

注意:

为了简单,我们没有考虑栈溢出情况。如果使用环境可能存在压栈溢出。我们需要改进StackPush函数,增加溢出判断。

int StackPush(STACK *Stack, void *Element)
{
    if (Stack->Depth >= MAX_STACK_DEPTH)
    {
        return -1;
    }

    Stack->Array[Stack->Depth++] = Element;
    return 0;
}

2. 单向链表定义和实现

单向链表在实际使用中非常常见,下面是其定义和实现,包含了用来验证的创建、释放、打印函数。

typedef struct _NODE
{
    struct _NODE *Next;
    int Value;
}
NODE;

void ListPrint(NODE *Head)
{
    while (Head)
    {
        printf("%d ", Head->Value);
        Head = Head->Next;
    }
    printf("\n");
}

void ListFree(NODE *Head)
{
    NODE *tmp = NULL;
    while (Head)
    {
        tmp = Head->Next;
        free(Head);
        Head = tmp;
    }
}

NODE *ListCreate(void)
{
    NODE *head = NULL, *lastNode = NULL, *curNode = NULL;
    int val = 0;

    printf("please input space-separated elements:\n");
    while (scanf("%d", &val) != EOF)
    {
        curNode = (NODE *)malloc(sizeof(NODE));
        if (curNode == NULL)
        {
            return head;    /* malloc failure, return current created list */
        }
        curNode->Value = val;
        curNode->Next = NULL;

        if (head == NULL)
        {
            head = curNode;
        }

        if (lastNode == NULL)
        {
            lastNode = curNode;
        }
        else
        {
            lastNode->Next = curNode;
            lastNode = curNode;
        }
        
        if (getchar() == '\n')
        {
            break;
        }
    }

    return head;
}

栈和链表综合使用示例--单向链表的反转:

通常我们使用多个指针逐步实现链表反转,但是栈天生就具备反转特性,所以使用栈来实现更简洁一些。

NODE *ListReverse(NODE *Head)
{
    NODE *curNode = NULL;
    STACK stack = {.Depth = 0, .Push = StackPush, .Pop = StackPop};

    if (Head == NULL)
    {
        return NULL;
    }

    while (Head)
    {
        stack.Push(&stack, (void *)Head);
        Head = Head->Next;
    }

    Head = (NODE *)stack.Pop(&stack);
    curNode = Head;
    while (stack.Depth > 0)
    {
        curNode->Next = (NODE *)stack.Pop(&stack);
        curNode = curNode->Next;
    }
    curNode->Next = NULL;
    
    return Head;
}

完整示例代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MAX_STACK_DEPTH 4096

typedef struct _STACK
{
    void *Array[MAX_STACK_DEPTH];
    int  Depth;
    void (*Push)(struct _STACK *,void *);
    void *(*Pop)(struct _STACK *);
}
STACK;

void StackPush(STACK *Stack, void *Element)
{
    if (Stack->Depth < MAX_STACK_DEPTH)
    {
        Stack->Array[Stack->Depth++] = Element;
    }
}

void *StackPop(STACK *Stack)
{
    if (Stack->Depth <= 0)
    {
        return NULL;
    }

    return Stack->Array[--Stack->Depth];
}

typedef struct _NODE
{
    struct _NODE *Next;
    int Value;
}
NODE;

void ListPrint(NODE *Head)
{
    while (Head)
    {
        printf("%d ", Head->Value);
        Head = Head->Next;
    }
    printf("\n");
}

void ListFree(NODE *Head)
{
    NODE *tmp = NULL;
    while (Head)
    {
        tmp = Head->Next;
        free(Head);
        Head = tmp;
    }
}

NODE *ListCreate(void)
{
    NODE *head = NULL, *lastNode = NULL, *curNode = NULL;
    int val = 0;

    printf("please input space-separated elements:\n");
    while (scanf("%d", &val) != EOF)
    {
        curNode = (NODE *)malloc(sizeof(NODE));
        if (curNode == NULL)
        {
            return head;    /* malloc failure, return current created list */
        }
        curNode->Value = val;
        curNode->Next = NULL;

        if (head == NULL)
        {
            head = curNode;
        }

        if (lastNode == NULL)
        {
            lastNode = curNode;
        }
        else
        {
            lastNode->Next = curNode;
            lastNode = curNode;
        }
        
        if (getchar() == '\n')
        {
            break;
        }
    }

    return head;
}

NODE *ListReverse(NODE *Head)
{
    NODE *curNode = NULL;
    STACK stack = {.Depth = 0, .Push = StackPush, .Pop = StackPop};

    if (Head == NULL)
    {
        return NULL;
    }

    while (Head)
    {
        stack.Push(&stack, (void *)Head);
        Head = Head->Next;
    }

    Head = (NODE *)stack.Pop(&stack);
    curNode = Head;
    while (stack.Depth > 0)
    {
        curNode->Next = (NODE *)stack.Pop(&stack);
        curNode = curNode->Next;
    }
    curNode->Next = NULL;
    
    return Head;
}

int main(int argc, char *argv[])
{
   NODE *list = NULL;

   list = ListCreate();
   ListPrint(list);
   list = ListReverse(list);
   ListPrint(list);
   ListFree(list);
   return 0;
}

3. 队列定义和实现

下面是一个队列的建议实现,遵循先进先出原则,从队头Pop弹出元素,从队尾Push压入元素。

#define MAX_QUEUE_LENGTH 4096

typedef struct _QUEUE
{
    void *Array[MAX_QUEUE_LENGTH];
    int Length;
    int Head;
    int Tail;
    void (*Push)(struct _QUEUE *, void *);
    void *(*Pop)(struct _QUEUE *);
}
QUEUE;

void QueuePush(QUEUE *Queue, void *Element)
{
    if (Queue->Length >= MAX_QUEUE_LENGTH)
    {
        return;
    }

    Queue->Array[Queue->Tail] = Element;
    if (Queue->Tail < MAX_QUEUE_LENGTH - 1)
    {
        Queue->Tail++;
    }
    else
    {
        Queue->Tail = 0;
    }
    Queue->Length++;
}

void *QueuePop(QUEUE *Queue)
{
    void *ele = NULL;

    if (Queue->Length <= 0)
    {
        return NULL;
    }

    ele = Queue->Array[Queue->Head];
    if (Queue->Head < MAX_QUEUE_LENGTH - 1)
    {
        Queue->Head++;
    }
    else
    {
        Queue->Head = 0;
    }
    Queue->Length--;

    return ele;
}

/*
 * Common Usage:
 * 1. QUEUE queue = {.Length = 0, .Head = 0, .Tail = 0, .Push = QueuePush, .Pop = QueuePop};
 *    queue.Push(&queue, (void *)ele);
 *    ele = (eleType)queue.Pop(&queue);
 * 2. QUEUE *queue = (QUEUE *)malloc(sizeof(QUEUE));
 *    queue->Length = queue->Head = queue->Tail = 0;
 *    queue->Push = QueuePush;
 *    queue->Pop = QueuePop;
 *    queue->Push(queue, (void *)ele);
 *    ele = (eleType)queue->Pop(queue);
 */

注意:

为了简单,我们没有考虑队列溢出情况。如果使用环境可能存在队列溢出。我们需要改进QueuePush函数,增加溢出判断。

int QueuePush(QUEUE *Queue, void *Element)
{
    if (Queue->Length >= MAX_QUEUE_LENGTH)
    {
        return -1;
    }

    Queue->Array[Queue->Tail] = Element;
    if (Queue->Tail < MAX_QUEUE_LENGTH - 1)
    {
        Queue->Tail++;
    }
    else
    {
        Queue->Tail = 0;
    }
    Queue->Length++;
    return 0;
}

队列和栈的示例--两个队列实现栈:

typedef struct _QUEUE_STACK
{
    QUEUE Queue1;
    QUEUE Queue2;
}
QUEUE_STACK;

int QueueStackDepth(QUEUE_STACK *Stack)
{
    if (Stack->Queue1.Length == 0 && Stack->Queue2.Length == 0)
    {
        return 0;
    }
    else if (Stack->Queue1.Length == 0)
    {
        return Stack->Queue2.Length;
    }
    else
    {
        return Stack->Queue1.Length;
    }
}

void QueueStackPush(QUEUE_STACK *Stack, void *Element)
{
    if (Stack->Queue1.Length > 0)
    {
        Stack->Queue1.Push(&Stack->Queue1, Element);
    }
    else
    {
        Stack->Queue2.Push(&Stack->Queue2, Element);
    }
}

void *QueueStackPop(QUEUE_STACK *Stack)
{
    QUEUE *popQueue = NULL, *pushQueue = NULL;
    void *ele = NULL;
    
    if (Stack->Queue1.Length == 0 && Stack->Queue2.Length == 0)
    {
        return NULL;
    }
    else if (Stack->Queue1.Length == 0)
    {
        pushQueue = &Stack->Queue1;
        popQueue = &Stack->Queue2;
    }
    else
    {
        pushQueue = &Stack->Queue2;
        popQueue = &Stack->Queue1;  
    }
    
    while (popQueue->Length > 1)
    {
        ele = popQueue->Pop(popQueue);
        pushQueue->Push(pushQueue, ele)
    }

    return popQueue->Pop(popQueue);
}

完整示例代码如下,直接gcc编译执行:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MAX_QUEUE_LENGTH 4096

typedef struct _QUEUE
{
    void *Array[MAX_QUEUE_LENGTH];
    int Length;
    int Head;
    int Tail;
    void (*Push)(struct _QUEUE *, void *);
    void *(*Pop)(struct _QUEUE *);
}
QUEUE;

void QueuePush(QUEUE *Queue, void *Element)
{
    if (Queue->Length >= MAX_QUEUE_LENGTH)
    {
        return;
    }

    Queue->Array[Queue->Tail] = Element;
    if (Queue->Tail < MAX_QUEUE_LENGTH - 1)
    {
        Queue->Tail++;
    }
    else
    {
        Queue->Tail = 0;
    }
    Queue->Length++;
}

void *QueuePop(QUEUE *Queue)
{
    void *ele = NULL;

    if (Queue->Length <= 0)
    {
        return NULL;
    }

    ele = Queue->Array[Queue->Head];
    if (Queue->Head < MAX_QUEUE_LENGTH - 1)
    {
        Queue->Head++;
    }
    else
    {
        Queue->Head = 0;
    }
    Queue->Length--;

    return ele;
}

typedef struct _QUEUE_STACK
{
    QUEUE Queue1;
    QUEUE Queue2;
}
QUEUE_STACK;

int QueueStackDepth(QUEUE_STACK *Stack)
{
    if (Stack->Queue1.Length == 0 && Stack->Queue2.Length == 0)
    {
        return 0;
    }
    else if (Stack->Queue1.Length == 0)
    {
        return Stack->Queue2.Length;
    }
    else
    {
        return Stack->Queue1.Length;
    }
}

void QueueStackPush(QUEUE_STACK *Stack, void *Element)
{
    if (Stack->Queue1.Length > 0)
    {
        Stack->Queue1.Push(&Stack->Queue1, Element);
    }
    else
    {
        Stack->Queue2.Push(&Stack->Queue2, Element);
    }
}

void *QueueStackPop(QUEUE_STACK *Stack)
{
    QUEUE *popQueue = NULL, *pushQueue = NULL;
    void *ele = NULL;

    if (Stack->Queue1.Length == 0 && Stack->Queue2.Length == 0)
    {
        return NULL;
    }
    else if (Stack->Queue1.Length == 0)
    {
        pushQueue = &Stack->Queue1;
        popQueue = &Stack->Queue2;
    }
    else
    {
        pushQueue = &Stack->Queue2;
        popQueue = &Stack->Queue1;
    }

    while (popQueue->Length > 1)
    {
        ele = popQueue->Pop(popQueue);
        pushQueue->Push(pushQueue, ele);
    }

    return popQueue->Pop(popQueue);
}

int main(int argc, char *argv[])
{
    QUEUE_STACK stack;
    int val = 0;

    stack.Queue1.Push = QueuePush;
    stack.Queue1.Pop = QueuePop;
    stack.Queue1.Length  = stack.Queue1.Head = stack.Queue1.Tail = 0;

    stack.Queue2.Push = QueuePush;
    stack.Queue2.Pop = QueuePop;
    stack.Queue2.Length  = stack.Queue2.Head = stack.Queue2.Tail = 0;

    printf("please input space-separated elements:\n")
    while (scanf("%d", &val) != EOF)
    {
        QueueStackPush(&stack, (void *)val);

        if (getchar() == '\n')
        {
            break;
        }
    }

    while (QueueStackDepth(&stack) > 0)
    {
        val = (int)QueueStackPop(&stack);
        printf("%d ", val);
    }
    printf("\n");

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮沉飘摇

码字不易,打赏随意。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值