栈实现队列:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define TYPE int
// 设计顺序栈结构
typedef struct ArrayStack
{
TYPE* ptr; // 存储元素内存首地址
size_t cal; // 栈的容量
size_t top; // 栈顶下标 从0开始 空增栈
}ArrayStack;
/*栈功能实现*/
// 创建
ArrayStack* create_array_stack(size_t cal)
{
// 为栈结构分配内存
ArrayStack* stack = malloc(sizeof(ArrayStack));
// 分配存储元素的内存
stack->ptr = malloc(sizeof(TYPE)*cal);
// 记录栈容量
stack->cal = cal;
// 记录栈顶位置,接下来要入栈的位置
stack->top = 0;
return stack;
}
// 销毁
void destory_array_stack(ArrayStack* stack)
{
free(stack->ptr);
free(stack);
}
// 栈空
bool empty_array_stack(ArrayStack* stack)
{
return 0 == stack->top;
}
// 栈满
bool full_array_stack(ArrayStack* stack)
{
return stack->top >= stack->cal;
}
// 入栈
bool push_array_stack(ArrayStack* stack,TYPE val)
{
if(full_array_stack(stack)) return false;
stack->ptr[stack->top++] = val;
return true;
}
// 出栈
bool pop_array_stack(ArrayStack* stack)
{
if(empty_array_stack(stack)) return false;
stack->top--;
return true;
}
// 栈顶
bool top_array_stack(ArrayStack* stack,TYPE* val)
{
if(empty_array_stack(stack)) return false;
*val = stack->ptr[stack->top-1];
return true;
}
/* 使用两个栈模拟队列功能 */
typedef struct Queue
{
ArrayStack* s1;
ArrayStack* s2;
}Queue;
// 创建队列
Queue* create_queue(size_t cal)
{
Queue* queue = malloc(sizeof(Queue));
queue->s1 = create_array_stack(cal);
queue->s2 = create_array_stack(cal);
return queue;
}
// 队满
bool full_queue(Queue* queue)
{
return full_array_stack(queue->s1) &&
full_array_stack(queue->s2);
}
// 队空
bool empty_queue(Queue* queue)
{
return empty_array_stack(queue->s1) &&
empty_array_stack(queue->s2);
}
// 入队
bool push_queue(Queue* queue,TYPE val)
{
if(full_array_stack(queue->s1))
{
if(!empty_array_stack(queue->s2)) return false;
while(!empty_array_stack(queue->s1))
{
TYPE top = 0;
top_array_stack(queue->s1,&top);
pop_array_stack(queue->s1);
push_array_stack(queue->s2,top);
}
}
printf("tail:%d\n",val); //测试
return push_array_stack(queue->s1,val);
}
// 出队
bool pop_queue(Queue* queue)
{
if(empty_array_stack(queue->s2))
{
if(empty_array_stack(queue->s1)) return false;
while(!empty_array_stack(queue->s1))
{
TYPE top = 0;
top_array_stack(queue->s1,&top);
pop_array_stack(queue->s1);
push_array_stack(queue->s2,top);
}
}
TYPE top = 0;
top_array_stack(queue->s2,&top);
printf("top:%d\n",top); //测试
return pop_array_stack(queue->s2);
}
int main(int argc,const char* argv[])
{
Queue* queue = create_queue(10);
for(int i=0; i<20; i++)
{
push_queue(queue,i);
}
while(!empty_queue(queue))
{
pop_queue(queue);
}
}
链表封装:
尾添加的效率低,对非法下标的判断下标的效率也非常低
1、单链表
结点:
数据域
指针域
例(节点):
typedef struct Node
{
TYPE data;
struct Node*next;
}Node;
单链表数据项:
头结点
尾结点
结点数量
例(链表)
typedef struct List
{
Node* head; //头指针
Node* tail; //尾指针
size_t size; //结点数量
}List;
2、静态链表
结点:
数据域
游标
typedef struct Node
{
int data;
int i; //游标
}
静态链表的结点存储在连续的内存中,通过游标来访问下一个结点
这种链表在插入删除时需要修改游标的值,而不用申请、释放结点内存就可以达到类似链式结构的效果
牺牲了随机访问的功能、也没达到链表动态申请内存的效果,只是给没有指针的编程语言实现链表的一种方式,适用范围不大
3、循环链表
链表的最后一个结点的next不再指向NULL,而是指向头结点,这种链表称为单向循环链表,简称循环链表,它的好处是可以通过任意结点来遍历整个链表
4、双向链表
结点:
前驱指针 prev
数据域
后继指针 next
typedef struct Node
{
struct Node* prev; // 前驱
TYPE data;
struct Node* next; // 后继
}Node;
数据项:
头结点
结点数量
// 双向链表
typedef struct DoubleList
{
Node* head;
size_t size;
}DoubleList;
特点:
1、在任意结点都可以遍历整个链表
2、相比单链表,删除、插入更直接
3、已知结点位置,可以选择从前往后或从后往前遍历,提高链表访问效率
5、Linux内核通用链表
链表的结点不能包含万物,就让万物来包含结点
typedef struct Node
{
struct Node* prev;
struct Node* next;
}Node;
// 创建链表
Node* create_list(void)
{
Node* head = malloc(sizeof(Node));
head->next = head;
head->prev = head;
return head;
}
6、通用链表
结点:
void* ptr;
指针域
运算:常规功能+回调函数
// 重定义了函数指针类型 新类型名叫Comper
// 定义函数指针变量 Comper cmp
// cmp即函数指针变量
typedef int (*Comper)(const void*,const void*);
// 通用链表结点
typedef struct Node
{
void* ptr;
struct Node* prev;
struct Node* next;
}Node;
// 通用链表结构
typedef struct List
{
Node* head;
size_t size;
}List;