/*!
\author LiuBao
\date 2011/3/4
\brief 设计包含min函数的栈
定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。
要求函数min、push以及pop的时间复杂度都是O(1)。
这里给出整个栈的宏实现,使用链式栈,仿照APR_RING设计宏函数。
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h> /* 比较函数中使用assert */
/*!
在任意结构体中使用本宏将使之成为最小栈节点结构体
\param elem_struct_name 栈节点结构体名
*/
#define MIN_STACK_ITEM_ENTRY(elem_struct_name) \
struct \
{ \
struct elem_struct_name * volatile min; \
struct elem_struct_name * volatile next; \
}
/*!
声明最小栈结构体
\param stack_struct_name 栈结构体名
\param elem_struct_name 栈节点结构体名
*/
#define MIN_STACK(stack_struct_name, elem_struct_name) \
struct stack_struct_name \
{ \
int (* volatile compare)(const struct elem_struct_name*, const struct elem_struct_name *);\
struct elem_struct_name * volatile top; \
}
/*!
用比较函数初始化最小化栈指针
\param stack_ptr 为初始化的栈指针
\param elem_compare_func 比较函数指针
*/
#define MIN_STACK_INIT(stack_ptr, elem_compare_func) \
do \
{ \
(stack_ptr)->compare = (elem_compare_func); \
(stack_ptr)->top = NULL; \
}while(0)
/*!
最小栈节点初始化
\param elem_ptr 栈节点指针
\param elem_entry_name 栈节点中入口成员名
*/
#define MIN_STACK_ELEM_INIT(elem_ptr, elem_entry_name) \
do \
{ \
(elem_ptr)->elem_entry_name.min = (elem_ptr); \
(elem_ptr)->elem_entry_name.next = NULL; \
}while(0)
/*!
向最小栈中压入一个节点
\param stack_ptr 栈指针
\param elem_ptr 栈节点指针
\param elem_entry_name 栈节点中入口成员名
*/
#define MIN_STACK_PUSH(stack_ptr, elem_ptr, elem_entry_name)\
do \
{ \
if((stack_ptr)->top) \
{ \
if((stack_ptr)->compare((stack_ptr)->top->elem_entry_name.min, (elem_ptr)) < 0)\
(elem_ptr)->elem_entry_name.min = (stack_ptr)->top->elem_entry_name.min;\
} \
(elem_ptr)->elem_entry_name.next = (stack_ptr)->top; \
(stack_ptr)->top = (elem_ptr); \
} \
while(0)
/*!
从最小栈中弹出一个节点到elem_ptr
\param stack_ptr 栈指针
\param elem_ptr 弹出的栈节点指针
\param elem_entry_name 栈节点中入口成员名
*/
#define MIN_STACK_POP(stack_ptr, elem_ptr, elem_entry_name) \
do \
{ \
elem_ptr = (stack_ptr)->top; \
if((stack_ptr)->top) \
(stack_ptr)->top = (stack_ptr)->top->elem_entry_name.next;\
}while(0)
/*!
获取最小栈中当前最小值(由比较函数确定)
\param stack_ptr 栈指针
\param elem_ptr 获取的栈最小节点指针
\param elem_entry_name 栈节点中入口成员名
*/
#define MIN_STACK_MIN(stack_ptr, elem_ptr, elem_entry_name) \
elem_ptr = (stack_ptr)->top->elem_entry_name.min; \
/*!
判断栈非空
\param stack_ptr 栈指针
*/
#define MIN_STACK_IS_NOT_EMPTY(stack_ptr) \
((stack_ptr) && (stack_ptr)->top) \
struct StackElem /// 栈节点结构体
{
int entryCanInAnyPosition; ///< 节点数据
MIN_STACK_ITEM_ENTRY(StackElem) entry; ///< 最小栈节点入口
int data; ///< 节点数据
double otherData; ///< 节点数据
};
MIN_STACK(Stack, StackElem); /// 栈结构体
/*!
节点比较函数
\param elem1 第一个节点指针
\param elem2 第二个节点指针
\return 若elem1小于elem2;返回负值;大于返回正值,等于返回0
*/
int CompareElem(const struct StackElem *elem1, const struct StackElem *elem2)
{
assert(elem1 && elem2);
return elem1->data - elem2->data;
}
int main()
{
int dataSet[] = {5, 6, -2, 3, 4, 2, -1, 3}; //测试数据集
struct Stack *s = malloc(sizeof(struct Stack));
if(s)
{
int i;
MIN_STACK_INIT(s, CompareElem); //初始化栈
/* 把dataSet数据压入栈 */
for(i = 0; i < sizeof(dataSet) / sizeof(int); ++i)
{
struct StackElem *e = malloc(sizeof(struct StackElem));
if(e)
{
MIN_STACK_ELEM_INIT(e, entry); //初始化栈节点
e->data = dataSet[i];
e->otherData = -dataSet[i];
MIN_STACK_PUSH(s, e, entry); //压入栈节点
printf("push:%p -> data:%d\n", e, e->data);
}
}
/* 把获取当前栈最小值并把栈中数据弹出 */
while(MIN_STACK_IS_NOT_EMPTY(s)) //循环判断栈非空
{
struct StackElem *e = NULL;
struct StackElem *min = NULL;
MIN_STACK_MIN(s, min, entry); //获取当前栈的最小节点到min
printf("min: %p -> data:%d\n", min, min->data);
MIN_STACK_POP(s, e, entry); //弹出栈节点到e
printf("pop: %p -> data:%d\n", e, e->data);
free(e);
}
}
printf("%p\n", s);
free(s);
return 0;
}