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;
}