【本文谢绝转载原文来自http://990487026.blog.51cto.com】
数据结构与算法 2:双向链表,栈,队列 双向链表 双向链表API 双向链表的正常的插入操作 双向链表的正常删除操作 双向链表的优缺点 栈 栈的顺序储存,选型[图] 栈的链式储存,选型[图] 栈的顺序储存设计与实现 栈的链式储存设计与实现 栈的典型应用1:就近匹配,语法检查器 栈的典型应用2:中缀转后缀 队列 队列顺序存储API 队列链式存储API
重点:
循环链表:
特殊处理:在头结点插入数据,必须遍历到尾节点
特殊处理:删除头结点数据,必须遍历到尾节点
双向链表:
引入三个辅助指针变量
特殊处理,空数据,在头结点插入数据相当于尾节点插入数据
双向链表API:
1,dlinklist.h
chunli@http://990487026.blog.51cto.com~/double_list$ cat dlinklist.h
#ifndef _MY_DLINKLIST_H_
#define _MY_DLINKLIST_H_
typedef void DLinkList;
/*
typedef struct _tag_DLinkListNode DLinkListNode;
struct _tag_DLinkListNode
{
DLinkListNode* next;
DLinkListNode* pre;
};
*/
typedef struct _tag_DLinkListNode
{
struct _tag_DLinkListNode* next;
struct _tag_DLinkListNode * pre;
}DLinkListNode;
DLinkList* DLinkList_Create();
void DLinkList_Destroy(DLinkList* list);
void DLinkList_Clear(DLinkList* list);
int DLinkList_Length(DLinkList* list);
int DLinkList_Insert(DLinkList* list, DLinkListNode* node, int pos);
DLinkListNode* DLinkList_Get(DLinkList* list, int pos);
DLinkListNode* DLinkList_Delete(DLinkList* list, int pos);
//-- add
DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node);
DLinkListNode* DLinkList_Reset(DLinkList* list);
DLinkListNode* DLinkList_Current(DLinkList* list);
DLinkListNode* DLinkList_Next(DLinkList* list);
DLinkListNode* DLinkList_Pre(DLinkList* list);
#endif
chunli@http://990487026.blog.51cto.com~/double_list$
2,dlinklist.c
chunli@http://990487026.blog.51cto.com~/double_list$ cat dlinklist.c
#include <stdio.h>
#include <malloc.h>
#include "dlinklist.h"
typedef struct _tag_DLinkList
{
DLinkListNode header;
DLinkListNode* slider;
int length;
} TDLinkList;
DLinkList* DLinkList_Create()
{
TDLinkList* ret = (TDLinkList*)malloc(sizeof(TDLinkList));
if( ret != NULL )
{
ret->length = 0;
ret->header.next = NULL;
ret->header.pre = NULL;
ret->slider = NULL;
}
return ret;
}
void DLinkList_Destroy(DLinkList* list)
{
if (list != NULL)
{
free(list);
}
}
void DLinkList_Clear(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
if( sList != NULL )
{
sList->length = 0;
sList->header.next = NULL;
sList->header.pre = NULL;
sList->slider = NULL;
}
}
int DLinkList_Length(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
int ret = -1;
if( sList != NULL )
{
ret = sList->length;
}
return ret;
}
//大家一定要注意:教科书不会告诉你 项目上如何用;哪些点是项目的重点
int DLinkList_Insert(DLinkList* list, DLinkListNode* node, int pos)
{
int ret = 0, i = 0;
TDLinkList* sList = (TDLinkList*)list;
if (list==NULL || node==NULL || pos<0)
{
return -1;
}
{
DLinkListNode* current = (DLinkListNode*)sList;
DLinkListNode* next = NULL; //需要增加next指针
for(i=0; (i<pos) && (current->next != NULL); i++)
{
current = current->next;
}
next = current->next;
//步骤1-2
current->next = node;
node->next = next;
//步骤3-4
if( next != NULL ) //当链表插入第一个元素,需要特殊处理
{
next->pre = node;
}
node->pre = current;
if( sList->length == 0 )
{
sList->slider = node; //当链表插入第一个元素处理游标
}
//若在0位置插入,需要特殊处理 新来结点next前pre指向null
if( current == (DLinkListNode*)sList )
{
node->pre = NULL;
}
sList->length++;
}
return ret;
}
DLinkListNode* DLinkList_Get(DLinkList* list, int pos)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
int i = 0;
if( (sList != NULL) && (0 <= pos) && (pos < sList->length) )
{
DLinkListNode* current = (DLinkListNode*)sList;
for(i=0; i<pos; i++)
{
current = current->next;
}
ret = current->next;
}
return ret;
}
//插入第一个节点
//删除的是最后一个结点,该是如何处理
DLinkListNode* DLinkList_Delete(DLinkList* list, int pos)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
int i = 0;
if (sList == NULL || pos <0 )
{
return NULL;
}
//if( (sList != NULL) && (0 <= pos) && (pos < sList->length) )
{
DLinkListNode* current = (DLinkListNode*)sList;
DLinkListNode* next = NULL; //需要增加next指针
for(i=0; i<pos; i++)
{
current = current->next;
}
ret = current->next;
next = ret->next;
//步骤1
current->next = next;
//步骤2
if( next != NULL )//需要特殊处理
{
next->pre = current;
if( current == (DLinkListNode*)sList ) //若第0个位置,需要特殊处理
{
next->pre = NULL;
}
}
if( sList->slider == ret )
{
sList->slider = next;
}
sList->length--;
}
return ret;
}
DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
int i = 0;
if( sList != NULL )
{
DLinkListNode* current = (DLinkListNode*)sList;
for(i=0; i<sList->length; i++)
{
if( current->next == node )
{
ret = current->next;
break;
}
current = current->next;
}
if( ret != NULL )
{
DLinkList_Delete(sList, i);
}
}
return ret;
}
DLinkListNode* DLinkList_Reset(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if( sList != NULL )
{
sList->slider = sList->header.next;
ret = sList->slider;
}
return ret;
}
DLinkListNode* DLinkList_Current(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if( sList != NULL )
{
ret = sList->slider;
}
return ret;
}
DLinkListNode* DLinkList_Next(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if( (sList != NULL) && (sList->slider != NULL) )
{
ret = sList->slider;
sList->slider = ret->next;
}
return ret;
}
DLinkListNode* DLinkList_Pre(DLinkList* list)
{
TDLinkList* sList = (TDLinkList*)list;
DLinkListNode* ret = NULL;
if( (sList != NULL) && (sList->slider != NULL) )
{
ret = sList->slider;
sList->slider = ret->pre;
}
return ret;
}
chunli@http://990487026.blog.51cto.com~/double_list$
3,测试程序 mia.c
chunli@http://990487026.blog.51cto.com~/double_list$ cat main.c
#include <stdio.h>
#include <stdlib.h>
#include "dlinklist.h"
struct Value
{
DLinkListNode node;
int v;
};
int main(int argc, char *argv[])
{
int i = 0;
DLinkList* list = DLinkList_Create();//创建双向链表
struct Value* pv = NULL;
struct Value v1, v2, v3, v4, v5;
v1.v = 1;
v2.v = 2;
v3.v = 3;
v4.v = 4;
v5.v = 5;
DLinkList_Insert(list, (DLinkListNode*)&v1, DLinkList_Length(list));//尾插法
DLinkList_Insert(list, (DLinkListNode*)&v2, DLinkList_Length(list));//尾插法
DLinkList_Insert(list, (DLinkListNode*)&v3, DLinkList_Length(list));//尾插法
DLinkList_Insert(list, (DLinkListNode*)&v4, DLinkList_Length(list));//尾插法
DLinkList_Insert(list, (DLinkListNode*)&v5, DLinkList_Length(list));//尾插法
for(i=0; i<DLinkList_Length(list); i++) //遍历链表
{
pv = (struct Value*)DLinkList_Get(list, i);
printf("遍历链表: %3d\n", pv->v);
}
printf("\n");
DLinkList_Delete(list, DLinkList_Length(list)-1);//删除尾节点
DLinkList_Delete(list, 0); //删除头头结点
//DLinkList_Delete(list, 3);
for(i=0; i<DLinkList_Length(list); i++)
{
pv = (struct Value*)DLinkList_Next(list);
printf("删除尾节点,头结点后 %3d\n", pv->v);
}
printf("\n");
DLinkList_Reset(list); //重置游标,头结点已经删除了,此时头结点就是值为2那个
DLinkList_Next(list); //游标下移,指向3了
pv = (struct Value*)DLinkList_Current(list);//显示当前游标指向的位置
printf("%d\n", pv->v);
DLinkList_DeleteNode(list, (DLinkListNode*)pv);//删除3,游标会下移
pv = (struct Value*)DLinkList_Current(list);
printf("%d\n", pv->v);//获取游标指向的元素,指向4
DLinkList_Pre(list); //游标往前跑
pv = (struct Value*)DLinkList_Current(list);
printf("%d\n", pv->v); //获取游标指向的元素,指向2
printf("此时链表长度,Length: %3d\n", DLinkList_Length(list));
DLinkList_Destroy(list);
return 0;
}
chunli@http://990487026.blog.51cto.com~/double_list$
编译运行:
chunli@http://990487026.blog.51cto.com~/double_list$ gcc main.c dlinklist.c -Wall && ./a.out
遍历链表: 1
遍历链表: 2
遍历链表: 3
遍历链表: 4
遍历链表: 5
删除尾节点,头结点后 2
删除尾节点,头结点后 3
删除尾节点,头结点后 4
3
4
2
此时链表长度,Length: 2
chunli@http://990487026.blog.51cto.com~/double_list$
双向链表的正常的插入操作
双向链表的正常删除操作
双向链表的优缺点
优点:双向链表在单链表的基础上增加了指向前驱的指针
功能上双向链表可以完全取代单链表的使用
循环链表的Next,Pre和Current操作可以高效的遍历链表中的所有元素
缺点:代码复杂
栈
栈的顺序储存,选型[图]
栈的链式储存,选型[图]
1,栈的顺序储存设计与实现
项目列表:
chunli@http://990487026.blog.51cto.com~/seq_stack$ tree . ├── main.c ├── seqlist.c ├── seqlist.h ├── seqstack.c └── seqstack.h 0 directories, 5 files
main测试程序文件
chunli@http://990487026.blog.51cto.com~/seq_stack$ cat main.c
#include <stdio.h>
#include "seqstack.h"
int main()
{
int my_data[10] = {0,1,2,3,4,5,6,7,8,9};//我的数据
int i = 0; //临时变量 for,while专用变量
SeqStack *stack = SeqStack_Create(10);//创建顺序表的大小
if(stack == NULL)
{
return -1;
}
for(i = 0;i<10;i++) //数据压栈
{
SeqStack_Push(stack,&my_data[i]);//把变量的地址压栈
}
printf("栈的容量大小为:%3d\n",SeqStack_Capacity(stack));//求栈容量的大小
printf("栈的实际长度为:%3d\n",SeqStack_Size(stack));//求栈的实际长度
printf("栈顶元素为:%3d\n",*(int*)SeqStack_Top(stack));//求栈的实际长度
while(SeqStack_Size(stack) > 0) //当栈实际长度大于0,就开始删除栈内元素
{
printf("被弹出的元素 %d\n",*(int*)SeqStack_Top(stack));
SeqStack_Pop(stack); //弹出栈内元素
}
printf("\n");
printf("栈的容量大小为:%3d\n",SeqStack_Capacity(stack));//求栈容量的大小
printf("栈的实际长度为:%3d\n",SeqStack_Size(stack));//求栈的实际长度
printf("栈顶元素为:%p\n",SeqStack_Top(stack));//求栈的实际长度
return 0;
}
chunli@http://990487026.blog.51cto.com~/seq_stack$
线性表函数实现文件,seqlist.c
chunli@http://990487026.blog.51cto.com~/seq_stack$ cat seqlist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "seqlist.h"
//申明一个结构体类型,用来存储线性表自己的信息
typedef struct _tag_SeqList
{
int length; //线性表的实际利用长度
int capacity; //线性表一共有多长
size_t *node;
}TSeqList;
//创建线性表
SeqList* SeqList_Create(int capacity)//相当于分配数组的大小
{
TSeqList * tmp = NULL;
//创建线性表的头,放在堆内存中
tmp = (TSeqList*)malloc(sizeof(TSeqList));
if(tmp == NULL)
{
printf("ERROR in (TSeqList*)malloc(sizeof(TSeqList)) \n");
return NULL;
}
//做个细心的人
memset(tmp,0,sizeof(TSeqList));
//根据capacity的大小,创建线性表的长度
tmp->node = (size_t *)malloc(sizeof(size_t*) *capacity );
if(tmp->node == NULL)
{
printf("ERROR in (unsigned int *)malloc(sizeof(unsigned int *) * capacity ) \n");
return NULL;
}
tmp->length = 0;
tmp->capacity = capacity;
return tmp;
}
//销毁链表
void SeqList_Destroy(SeqList* list)
{
TSeqList *tlist = NULL;
if(list == NULL)
{
printf("list == NULL \n");
return;
}
tlist = (TSeqList *)list;
if(tlist ->node != NULL)
{
free(tlist->node);//释放存储内存区
}
free(tlist); //释放线性表头
return ;
}
//清空链表的长度
void SeqList_Clear(SeqList* list)
{
TSeqList *tlist = NULL;
if(list == NULL)
{
printf("list == NULL \n");
return;
}
tlist = (TSeqList *)list;
tlist->length = 0;
return ;
}
//返回线性表的长度
int SeqList_Length(SeqList* list)
{
TSeqList *tlist = NULL;
if(list == NULL)
{
printf("list == NULL \n");
return -1;
}
tlist = (TSeqList *)list;
return tlist->length;
}
//返回线性表的容量
int SeqList_Capacity(SeqList* list)
{
TSeqList *tlist = NULL;
if(list == NULL)
{
printf("list == NULL \n");
return -1;
}
tlist = (TSeqList *)list;
return tlist->capacity;
}
//节点的插入
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos)
{
if(list == NULL || node == NULL || pos <0)
{
printf("list == NULL || node == NULL \n");
return -1;
}
TSeqList *tlist = NULL;
tlist = (TSeqList *)list;
//判断容量是不是 满了
if(tlist->length >= tlist->capacity)
{
printf("插入失败,线性表已经装满了\n");
}
//容错修正 20个容量,已经用到6,要求在10插入
if(pos >= tlist->length )
{
pos = tlist->length;
}
int i = 0;
for(i = tlist->length;i > pos;i--)
{
tlist->node[i] = tlist->node[i-1];
}
tlist->length ++;
tlist->node[pos] = *(size_t *)node;
return 0;
}
SeqListNode* SeqList_Get(SeqList* list, int pos)
{
if(list == NULL || pos <0)
{
printf("检测到线性表为空,返回NULL \n");
return NULL;
}
TSeqList *tlist = NULL;
tlist = (TSeqList *)list;
return &tlist->node[pos];
}
SeqListNode* SeqList_Delete(SeqList* list, int pos)
{
if(list == NULL || pos <0)
{
printf("线性表为空 \n");
return NULL;
}
TSeqList *tlist = NULL;
tlist = (TSeqList *)list;
int i = 0;
for(i = pos+1;i<tlist->length;i++)
{
tlist->node[i-1] = tlist->node[i];
}
tlist->length --;
return NULL;
}
chunli@http://990487026.blog.51cto.com~/seq_stack$
线性表函数声明文件,seqlist.h
chunli@http://990487026.blog.51cto.com~/seq_stack$ cat seqlist.h
#ifndef __MY_SEQLIST_H__
#define __MY_SEQLIST_H__
typedef void SeqList;
typedef void SeqListNode;
SeqList* SeqList_Create(int capacity);
void SeqList_Destroy(SeqList* list);
void SeqList_Clear(SeqList* list);
int SeqList_Length(SeqList* list);
int SeqList_Capacity(SeqList* list);
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos);
SeqListNode* SeqList_Get(SeqList* list, int pos);
SeqListNode* SeqList_Delete(SeqList* list, int pos);
#endif //__MY_SEQLIST_H__
chunli@http://990487026.blog.51cto.com~/seq_stack$
栈函数实现文件seqstack.c
chunli@http://990487026.blog.51cto.com~/seq_stack$ cat seqstack.c
#include <stdio.h>
#include "seqstack.h"
#include "seqlist.h"
SeqStack* SeqStack_Create(int capacity) //创建一个顺序栈
{
return SeqList_Create(capacity);//创建一个线程表
}
void SeqStack_Destroy(SeqStack* stack)//销毁顺序栈
{
SeqList_Destroy(stack) ;//销毁线性表
}
void SeqStack_Clear(SeqStack* stack)//清空顺序栈
{
SeqList_Clear(stack) ;//清空线性表
}
int SeqStack_Push(SeqStack* stack, void* item)//往栈中压入数据,相当于在尾部插入元素
{
return SeqList_Insert(stack,item,SeqList_Length(stack));
}
void* SeqStack_Pop(SeqStack* stack) //从栈中弹出元素,相当于从链表的尾部删除元素
{
return SeqList_Delete(stack,SeqList_Length(stack)-1);
}
void* SeqStack_Top(SeqStack* stack)//获取栈顶元素,相当于获取线性表的尾部元素
{
return SeqList_Get(stack,SeqList_Length(stack)-1);
}
int SeqStack_Size(SeqStack* stack)//获取栈的大小,相当于获取线性表的实际长度
{
return SeqList_Length(stack);
}
int SeqStack_Capacity(SeqStack* stack)//获取栈的容量,相当于获取线性表顺序存储的容量
{
return SeqList_Capacity(stack) ;
}
chunli@http://990487026.blog.51cto.com~/seq_stack$
栈函数声明文件seqstack.h
chunli@http://990487026.blog.51cto.com~/seq_stack$ cat seqstack.h
// seqstack.h
#ifndef _MY_SEQSTACK_H_
#define _MY_SEQSTACK_H_
typedef void SeqStack;
SeqStack* SeqStack_Create(int capacity);
void SeqStack_Destroy(SeqStack* stack);
void SeqStack_Clear(SeqStack* stack);
int SeqStack_Push(SeqStack* stack, void* item);
void* SeqStack_Pop(SeqStack* stack);
void* SeqStack_Top(SeqStack* stack);
int SeqStack_Size(SeqStack* stack);
int SeqStack_Capacity(SeqStack* stack);
#endif //_MY_SEQSTACK_H_
chunli@http://990487026.blog.51cto.com~/seq_stack$
编译运行:
chunli@http://990487026.blog.51cto.com~/seq_stack$ gcc main.c seqstack.c seqlist.c -Wall -g && ./a.out
栈的容量大小为: 10
栈的实际长度为: 10
栈顶元素为: 9
被弹出的元素 9
被弹出的元素 8
被弹出的元素 7
被弹出的元素 6
被弹出的元素 5
被弹出的元素 4
被弹出的元素 3
被弹出的元素 2
被弹出的元素 1
被弹出的元素 0
栈的容量大小为: 10
栈的实际长度为: 0
检测到线性表为空,返回NULL
栈顶元素为:(nil)
chunli@http://990487026.blog.51cto.com~/seq_stack$
2,栈的链式储存设计与实现,[难度大]
项目文件:
chunli@http://990487026.blog.51cto.com~/link_stack$ tree
.
├── linklist.c
├── linklist.h
├── linkstack.c
├── linkstack.h
└── main.c
0 directories, 5 files
linklist.c链表函数实现文件
chunli@http://990487026.blog.51cto.com~/link_stack$ cat linklist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linklist.h"
typedef struct _tag_LinkList
{
//这个句柄里面,需要保存所有节点信息。需要有一个起始点
//就是带头节点的链表。。。
LinkListNode header;
int length;
}TLinkList;
LinkList* LinkList_Create()
{
TLinkList *ret = (TLinkList *)malloc(sizeof(TLinkList));
if (ret == NULL)
{
return NULL;
}
//memset(ret, 0, sizeof(TLinkList));
ret->header.next = NULL;
ret->length = 0;
return ret;
}
void LinkList_Destroy(LinkList* list)
{
if (list == NULL)
{
return ;
}
free(list);
return ;
}
void LinkList_Clear(LinkList* list)
{
TLinkList *tList =NULL;
if (list == NULL)
{
return ;
}
tList = (TLinkList *)list;
tList->length = 0;
tList->header.next = NULL;
return ;
}
int LinkList_Length(LinkList* list)
{
TLinkList *tList = (TLinkList *)list;
if (tList == NULL)
{
return -1;
}
return tList->length;
}
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos)
{
int i = 0;
TLinkList *tList = NULL;
LinkListNode *current = NULL;
tList = (TLinkList *)list;
if (list==NULL || node==NULL) //modify by bombing 2014.06.26
{
return -1;
}
//准备环境让辅助指针变量 指向链表头节点
current = &tList->header;
for (i=0; i<pos &&(current->next!=NULL); i++)
{
current = current->next;
}
//让node节点链接后续链表
node->next = current->next ;
//让前边的链表。链接node
current->next = node;
tList->length ++;
return 0;
}
LinkListNode* LinkList_Get(LinkList* list, int pos)
{
int i = 0;
TLinkList *tList = NULL;
LinkListNode *current = NULL;
LinkListNode *ret = NULL;
tList = (TLinkList *)list;
if (list == NULL || pos <0 ||pos>=tList->length)
{
return NULL;
}
//准备环境让辅助指针变量 指向链表头节点
current = &tList->header;
for (i=0; i<pos &&(current->next!=NULL); i++)
{
current = current->next;
}
ret = current->next;
return ret;
}
LinkListNode* LinkList_Delete(LinkList* list, int pos)
{
int i = 0;
TLinkList *tList = NULL;
LinkListNode *current = NULL;
LinkListNode *ret = NULL;
tList = (TLinkList *)list;
if (list == NULL || pos <0 ||pos>=tList->length)
{
return NULL;
}
//准备环境让辅助指针变量 指向链表头节点
current = &tList->header;
for (i=0; i<pos &&(current->next!=NULL); i++)
{
current = current->next;
}
ret = current->next;
//删除算法
current->next =ret->next;
tList->length--;
return ret;
}
chunli@http://990487026.blog.51cto.com~/link_stack$
linklist.h链表函数声明文件
chunli@http://990487026.blog.51cto.com~/link_stack$ cat linklist.h
#ifndef _MYLINKLIST_H_
#define _MYLINKLIST_H_
typedef void LinkList;
/*
typedef struct _tag_LinkListNode LinkListNode;
struct _tag_LinkListNode
{
LinkListNode* next;
};
*/
typedef struct _tag_LinkListNode
{
struct _tag_LinkListNode* next;
}LinkListNode;
LinkList* LinkList_Create();
void LinkList_Destroy(LinkList* list);
void LinkList_Clear(LinkList* list);
int LinkList_Length(LinkList* list);
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos);
LinkListNode* LinkList_Get(LinkList* list, int pos);
LinkListNode* LinkList_Delete(LinkList* list, int pos);
#endif
chunli@http://990487026.blog.51cto.com~/link_stack$
linkstack.c栈函数声明文件
chunli@http://990487026.blog.51cto.com~/link_stack$ cat linkstack.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linkstack.h"
#include "linklist.h"
typedef struct linkstack_node
{
LinkListNode node;//让万象包含链表
void *item; //栈的业务节点
}linkstack_node;
LinkStack* LinkStack_Create()//创建一个栈,相当于创建一个线性表
{
return LinkList_Create();
}
void LinkStack_Destroy(LinkStack* stack)//销毁一个栈,相当于销毁一个线性表
{
LinkStack_Clear(stack);
LinkList_Destroy(stack);
return ;
}
void LinkStack_Clear(LinkStack* stack)//清空一个栈,相当于清空一个线性表
{
//清空栈的时候,涉及到元素生命周期管理
if(stack == NULL)
{
return;
}
while(LinkStack_Size(stack) > 0)
{
LinkStack_Pop(stack);//释放链表节点
}
return ;
}
int LinkStack_Push(LinkStack* stack, void* item)//向线性表的头部插入元素
{
linkstack_node *tmp = (linkstack_node*)malloc(sizeof(linkstack_node));
if(tmp == NULL)
{
return -1;
}
memset(tmp,0,sizeof(linkstack_node));
tmp->item = item;
int ret = LinkList_Insert(stack,(LinkListNode*)tmp,0);//把数据转换成链表的业务节点
if(ret != 0)
{
printf("数据插入失败!\n");
if(tmp != NULL)//业务失败时,及时释放内存
{
free(tmp);
}
return -2;
}
return 0;
}
void* LinkStack_Pop(LinkStack* stack)//相当于从线性表的头部弹出元素
{
linkstack_node *tmp = NULL;//返回一个linkstack_node
tmp = (linkstack_node *)LinkList_Delete(stack,0);//把链表节点转成业务节点
if(tmp == NULL)
{
return NULL;
}
void *item = tmp->item;//还原业务节点
free(tmp); //干掉链表节点
return item;
}
void* LinkStack_Top(LinkStack* stack)//获取栈顶元素
{
linkstack_node *tmp = (linkstack_node *)LinkList_Get(stack,0);
if(tmp == NULL)
{
return NULL;
}
return tmp->item;
}
int LinkStack_Size(LinkStack* stack)//求栈的大小,相当于求线性表的额length
{
return LinkList_Length(stack);
}
chunli@http://990487026.blog.51cto.com~/link_stack$
linkstack.h栈函数实现文件
chunli@http://990487026.blog.51cto.com~/link_stack$ cat linkstack.h
#ifndef _MY_LINKSTACK_H_
#define _MY_LINKSTACK_H_
typedef void LinkStack;
LinkStack* LinkStack_Create();
void LinkStack_Destroy(LinkStack* stack);
void LinkStack_Clear(LinkStack* stack);
int LinkStack_Push(LinkStack* stack, void* item);
void* LinkStack_Pop(LinkStack* stack);
void* LinkStack_Top(LinkStack* stack);
int LinkStack_Size(LinkStack* stack);
#endif //_MY_LINKSTACK_H_
chunli@http://990487026.blog.51cto.com~/link_stack$
main.c测试程序
chunli@http://990487026.blog.51cto.com~/link_stack$ cat main.c
// gcc main.c linkstack.c linklist.c -Wall -g && ./a.out
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linkstack.h"
#define MAX 20
int main()
{
int i = 0;
int ret = 0;
int a[MAX] ={0};
LinkStack * stack = LinkStack_Create();
if(stack == NULL)
{
return -1;
}
printf("开始压栈 ... ");
for(i = 0;i<MAX;i++)//数据压栈
{
a[i] = i*i+i+1;
ret = LinkStack_Push(stack,&a[i]);
if(ret != 0)
{
printf("error LinkStack_Push %d\n",ret);
}
}
printf("压栈完毕\n");
printf("栈的大小%d\n",LinkStack_Size(stack));
printf("栈顶元素%d\n",*(int *)LinkStack_Top(stack));
while(LinkStack_Size(stack) > 0)
{
printf("正在删除栈顶元素%d\n",*(int *)LinkStack_Top(stack));
LinkStack_Pop(stack);
}
LinkStack_Destroy(stack);//删除栈
return 0;
}
chunli@http://990487026.blog.51cto.com~/link_stack$
编译运行:
chunli@http://990487026.blog.51cto.com~/link_stack$ gcc main.c linkstack.c linklist.c -Wall -g && ./a.out
开始压栈 ... 压栈完毕
栈的大小20
栈顶元素381
正在删除栈顶元素381
正在删除栈顶元素343
正在删除栈顶元素307
正在删除栈顶元素273
正在删除栈顶元素241
正在删除栈顶元素211
正在删除栈顶元素183
正在删除栈顶元素157
正在删除栈顶元素133
正在删除栈顶元素111
正在删除栈顶元素91
正在删除栈顶元素73
正在删除栈顶元素57
正在删除栈顶元素43
正在删除栈顶元素31
正在删除栈顶元素21
正在删除栈顶元素13
正在删除栈顶元素7
正在删除栈顶元素3
正在删除栈顶元素1
chunli@http://990487026.blog.51cto.com~/link_stack$
3,栈的典型应用1:就近匹配,语法检查器
几乎所有的编译器都具有检测括号是否匹配的能力
如何实现编译器中的符号成对检测?
#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0;
算法思路
从第一个字符开始扫描
当遇见普通字符时忽略,当遇见左符号时压入栈中
当遇见右符号时从栈中弹出栈顶符号,并进行匹配
匹配成功:继续读入下一个字符
匹配失败:立即停止,并报错
结束:
成功: 所有字符扫描完毕,且栈为空
失败:匹配失败或所有字符扫描完毕但栈非空
当需要检测成对出现但又互不相邻的事物时
可以使用栈“后进先出”的特性
栈非常适合于需要“就近匹配”的场合
计算机的本质工作就是做数学运算,那计算机可以读入字符串
“9 + (3 - 1) * 5 + 8 / 2”并计算值吗?
项目文件:
chunli@http://990487026.blog.51cto.com~/link_stack$ tree
.
├── linklist.c
├── linklist.h
├── linkstack.c
├── linkstack.h
└── main.c
0 directories, 5 files
除了main.c文件与之前的文件不一样
linklist.c,linklist.h,linkstack.c,linkstack.h和上面的一样
main.c
chunli@http://990487026.blog.51cto.com~/link_stack$ cat main.c
// gcc main.c linkstack.c linklist.c -Wall -g && ./a.out
#include <stdio.h>
#include <stdlib.h>
#include "linkstack.h"
int isLeft(char c)
{
int ret = 0;
switch(c)
{
case '<':
case '(':
case '[':
case '{':
case '\'':
case '\"':
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
int isRight(char c)
{
int ret = 0;
switch(c)
{
case '>':
case ')':
case ']':
case '}':
case '\'':
case '\"':
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
int match(char left, char right)
{
int ret = 0;
switch(left)
{
case '<':
ret = (right == '>');
break;
case '(':
ret = (right == ')');
break;
case '[':
ret = (right == ']');
break;
case '{':
ret = (right == '}');
break;
case '\'':
ret = (right == '\'');
break;
case '\"':
ret = (right == '\"');
break;
default:
ret = 0;
break;
}
return ret;
}
int scanner(const char* code)
{
LinkStack* stack = LinkStack_Create();
int ret = 0;
int i = 0;
while( code[i] != '\0' )
{
if( isLeft(code[i]) )
{
LinkStack_Push(stack, (void*)(code + i)); //&code[i]
}
if( isRight(code[i]) )
{
char* c = (char*)LinkStack_Pop(stack);
if( (c == NULL) || !match(*c, code[i]) )
{
printf("%c does not match!\n", code[i]);
ret = 0;
break;
}
}
i++;
}
if( (LinkStack_Size(stack) == 0) && (code[i] == '\0') )
{
printf("Succeed!\n");
ret = 1;
}
else
{
printf("Invalid code!\n");
ret = 0;
}
LinkStack_Destroy(stack);
return ret;
}
int main()
{
//const char* code = "#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0; ";//Invalid code!
const char* code = "#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0; }";//Succeed!
scanner(code);
return 0;
}
chunli@http://990487026.blog.51cto.com~/link_stack$
编译运行:
chunli@http://990487026.blog.51cto.com~/link_stack$ gcc main.c linkstack.c linklist.c -Wall -g && ./a.out
Succeed!
chunli@http://990487026.blog.51cto.com~/link_stack$
4,栈的典型应用2:中缀转后缀
计算机的本质工作就是做数学运算,那计算机可以读入字符串
“9 + (3 - 1) * 5 + 8 / 2”并计算值吗?
后缀表达式 ==?符合计算机运算
波兰科学家在20世纪50年代提出了一种将运算符放在数字后面的后缀表达式对应的,
我们习惯的数学表达式叫做中缀表达式===》符合人类思考习惯
实例:
5 + 4=> 5 4 +
1 + 2 * 3 => 1 2 3 * +
8 + ( 3 – 1 ) * 5 => 8 3 1 – 5 * +
中缀表达式符合人类的阅读和思维习惯
后缀表达式符合计算机的“运算习惯”
如何将中缀表达式转换成后缀表达式?
中缀转后缀算法:
遍历中缀表达式中的数字和符号
对于数字:直接输出
对于符号:
左括号:进栈
运算符号:与栈顶符号进行优先级比较
若栈顶符号优先级低:此符合进栈 (默认栈顶若是左括号,左括号优先级最低)
若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
右括号:将栈顶符号弹出并输出,直到匹配左括号
遍历结束:将栈中的所有符号弹出并输出
中缀转后缀
项目文件:
chunli@http://990487026.blog.51cto.com~/link_stack$ tree
.
├── linklist.c
├── linklist.h
├── linkstack.c
├── linkstack.h
└── main.c
0 directories, 8 files
除了main.c文件与之前的文件不一样,linklist.c,linklist.h,linkstack.c,linkstack.h和上面的一样
chunli@http://990487026.blog.51cto.com~/link_stack$ cat main.c
// gcc main.c linkstack.c linklist.c -Wall -g && ./a.out
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linkstack.h"
size_t isNumber(char c)
{
return ('0' <= c) && (c <= '9');
}
size_t isOperator(char c)
{
return (c == '+') || (c == '-') || (c == '*') || (c == '/');
}
size_t isLeft(char c)
{
return (c == '(');
}
size_t isRight(char c)
{
return (c == ')');
}
size_t priority(char c)//求符号的优先级
{
size_t ret = 0;
if( (c == '+') || (c == '-') )
{
ret = 1;
}
if( (c == '*') || (c == '/') )
{
ret = 2;
}
return ret;
}
void output(char c)
{
if( c != '\0' )
{
printf("%c", c);
}
}
void transform(const char* exp)
{
size_t i = 0;
LinkStack* stack = LinkStack_Create();
while( exp[i] != '\0' )
{
if( isNumber(exp[i]) )
{
output(exp[i]);
}
else if( isOperator(exp[i]) )
{
while( priority(exp[i]) <= priority((char)(size_t)LinkStack_Top(stack)) )
{
output((char)(size_t)LinkStack_Pop(stack));
}
LinkStack_Push(stack, (void*)(size_t)exp[i]);
}
else if( isLeft(exp[i]) )
{
LinkStack_Push(stack, (void*)(size_t)exp[i]);
}
else if( isRight(exp[i]) )
{
//char c = '\0';
while( !isLeft((char)(size_t)LinkStack_Top(stack)) )
{
output((char)(size_t)LinkStack_Pop(stack));
}
LinkStack_Pop(stack);
}
else
{
printf("Invalid expression!");
break;
}
i++;
}
while( (LinkStack_Size(stack) > 0) && (exp[i] == '\0') )
{
output((char)(size_t)LinkStack_Pop(stack));
}
LinkStack_Destroy(stack);
}
int main()
{
const char *str = "8+(3-1)*5";
printf("中缀表达式:%s\n",str);
printf("后缀表达式:");
transform(str);
printf("\n");
return 0;
}
chunli@http://990487026.blog.51cto.com~/link_stack$ gcc main.c linkstack.c linklist.c -Wall -g && ./a.out
中缀表达式:8+(3-1)*5
后缀表达式:831-5*+
chunli@http://990487026.blog.51cto.com~/link_stack$
队列
1,队列顺序存储
项目文件:
chunli@http://990487026.blog.51cto.com~/seq_queue$ tree
.
├── main.c
├── seqlist.c
├── seqlist.h
├── seqqueue.c
└── seqqueue.h
0 directories, 5 files
main.c
chunli@http://990487026.blog.51cto.com~/seq_queue$ cat main.c
#include <stdio.h>
#include "seqqueue.h"
#define MAX 20
int main()
{
int ret = 0;
int i = 0;
int arr[MAX] = {0};
SeqQueue *queue = SeqQueue_Create(MAX);
if(queue == NULL)
{
return -1;
}
for(i=0;i<MAX;i++)
{
arr[i] = i*i+i+1;
ret = SeqQueue_Append(queue,&arr[i]);
if(ret != 0)
{
printf("error in SeqQueue_Append %d\n",ret);
return -2;
}
}
printf("队列的长度%d\n",SeqQueue_Length(queue));
printf("队列的头元素%d\n",*(int*)SeqQueue_Header(queue));
while(SeqQueue_Length(queue) > 0)
{
printf("正在出列%3d\n",*(int*)SeqQueue_Header(queue));
SeqQueue_Retrieve(queue);
}
SeqQueue_Destroy(queue);
return 0;
}
chunli@http://990487026.blog.51cto.com~/seq_queue$
seqlist.c
chunli@http://990487026.blog.51cto.com~/seq_queue$ cat seqlist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "seqlist.h"
//申明一个结构体类型,用来存储线性表自己的信息
typedef struct _tag_SeqList
{
int length; //线性表的实际利用长度
int capacity; //线性表一共有多长
size_t *node;
}TSeqList;
//创建线性表
SeqList* SeqList_Create(int capacity)//相当于分配数组的大小
{
TSeqList * tmp = NULL;
//创建线性表的头,放在堆内存中
tmp = (TSeqList*)malloc(sizeof(TSeqList));
if(tmp == NULL)
{
printf("ERROR in (TSeqList*)malloc(sizeof(TSeqList)) \n");
return NULL;
}
//做个细心的人
memset(tmp,0,sizeof(TSeqList));
//根据capacity的大小,创建线性表的长度
tmp->node = (size_t *)malloc(sizeof(size_t*) *capacity );
if(tmp->node == NULL)
{
printf("ERROR in (unsigned int *)malloc(sizeof(unsigned int *) * capacity ) \n");
return NULL;
}
tmp->length = 0;
tmp->capacity = capacity;
return tmp;
}
//销毁链表
void SeqList_Destroy(SeqList* list)
{
TSeqList *tlist = NULL;
if(list == NULL)
{
printf("list == NULL \n");
return;
}
tlist = (TSeqList *)list;
if(tlist ->node != NULL)
{
free(tlist->node);//释放存储内存区
}
free(tlist); //释放线性表头
return ;
}
//清空链表的长度
void SeqList_Clear(SeqList* list)
{
TSeqList *tlist = NULL;
if(list == NULL)
{
printf("list == NULL \n");
return;
}
tlist = (TSeqList *)list;
tlist->length = 0;
return ;
}
//返回线性表的长度
int SeqList_Length(SeqList* list)
{
TSeqList *tlist = NULL;
if(list == NULL)
{
printf("list == NULL \n");
return -1;
}
tlist = (TSeqList *)list;
return tlist->length;
}
//返回线性表的容量
int SeqList_Capacity(SeqList* list)
{
TSeqList *tlist = NULL;
if(list == NULL)
{
printf("list == NULL \n");
return -1;
}
tlist = (TSeqList *)list;
return tlist->capacity;
}
//节点的插入
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos)
{
if(list == NULL || node == NULL || pos <0)
{
printf("list == NULL || node == NULL \n");
return -1;
}
TSeqList *tlist = NULL;
tlist = (TSeqList *)list;
//判断容量是不是 满了
if(tlist->length >= tlist->capacity)
{
printf("插入失败,线性表已经装满了\n");
}
//容错修正 20个容量,已经用到6,要求在10插入
if(pos >= tlist->length )
{
pos = tlist->length;
}
int i = 0;
for(i = tlist->length;i > pos;i--)
{
tlist->node[i] = tlist->node[i-1];
}
tlist->length ++;
tlist->node[pos] = *(size_t *)node;
return 0;
}
SeqListNode* SeqList_Get(SeqList* list, int pos)
{
if(list == NULL || pos <0)
{
printf("检测到线性表为空,返回NULL \n");
return NULL;
}
TSeqList *tlist = NULL;
tlist = (TSeqList *)list;
return &tlist->node[pos];
}
SeqListNode* SeqList_Delete(SeqList* list, int pos)
{
if(list == NULL || pos <0)
{
printf("线性表为空 \n");
return NULL;
}
TSeqList *tlist = NULL;
tlist = (TSeqList *)list;
int i = 0;
for(i = pos+1;i<tlist->length;i++)
{
tlist->node[i-1] = tlist->node[i];
}
tlist->length --;
return NULL;
}
chunli@http://990487026.blog.51cto.com~/seq_queue$
seqlist.h
chunli@http://990487026.blog.51cto.com~/seq_queue$ cat seqlist.h
#ifndef __MY_SEQLIST_H__
#define __MY_SEQLIST_H__
typedef void SeqList;
typedef void SeqListNode;
SeqList* SeqList_Create(int capacity);
void SeqList_Destroy(SeqList* list);
void SeqList_Clear(SeqList* list);
int SeqList_Length(SeqList* list);
int SeqList_Capacity(SeqList* list);
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos);
SeqListNode* SeqList_Get(SeqList* list, int pos);
SeqListNode* SeqList_Delete(SeqList* list, int pos);
#endif //__MY_SEQLIST_H__
chunli@http://990487026.blog.51cto.com~/seq_queue$
seqqueue.c
chunli@http://990487026.blog.51cto.com~/seq_queue$ cat seqqueue.c
#include "seqqueue.h"
#include "seqlist.h"
//创建队列,相当于创建一个线性表
SeqQueue* SeqQueue_Create(int capacity)
{
return SeqList_Create(capacity);
}
void SeqQueue_Destroy(SeqQueue* queue)
{
SeqList_Destroy(queue);
}
void SeqQueue_Clear(SeqQueue* queue)
{
SeqList_Clear(queue);
}
//向队列中添加元素,相当于 向线性表中,尾部插入元素
int SeqQueue_Append(SeqQueue* queue, void* item)
{
return SeqList_Insert(queue, item, SeqList_Length(queue));
}
//从队列中删除元素,相当于从线性表中删除第一个元素
void* SeqQueue_Retrieve(SeqQueue* queue)
{
return SeqList_Delete(queue, 0);
}
void* SeqQueue_Header(SeqQueue* queue)
{
return SeqList_Get(queue, 0);
}
int SeqQueue_Length(SeqQueue* queue)
{
return SeqList_Length(queue);
}
int SeqQueue_Capacity(SeqQueue* queue)
{
return SeqList_Capacity(queue);
}
chunli@http://990487026.blog.51cto.com~/seq_queue$
seqqueue.h
chunli@http://990487026.blog.51cto.com~/seq_queue$ cat seqqueue.h
#ifndef _MY_SEQQUEUE_H_
#define _MY_SEQQUEUE_H_
typedef void SeqQueue;
SeqQueue* SeqQueue_Create(int capacity);
void SeqQueue_Destroy(SeqQueue* queue);
void SeqQueue_Clear(SeqQueue* queue);
int SeqQueue_Append(SeqQueue* queue, void* item);
void* SeqQueue_Retrieve(SeqQueue* queue);
void* SeqQueue_Header(SeqQueue* queue);
int SeqQueue_Length(SeqQueue* queue);
int SeqQueue_Capacity(SeqQueue* queue);
#endif //_MY_SEQQUEUE_H_
chunli@http://990487026.blog.51cto.com~/seq_queue$
编译运行:
chunli@http://990487026.blog.51cto.com~/seq_queue$ gcc main.c seqqueue.c seqlist.c -Wall -g&& ./a.out
队列的长度20
队列的头元素1
正在出列 1
正在出列 3
正在出列 7
正在出列 13
正在出列 21
正在出列 31
正在出列 43
正在出列 57
正在出列 73
正在出列 91
正在出列111
正在出列133
正在出列157
正在出列183
正在出列211
正在出列241
正在出列273
正在出列307
正在出列343
正在出列381
chunli@http://990487026.blog.51cto.com~/seq_queue$
2,队列链式储存设计与实现:
项目文件:
chunli@http://990487026.blog.51cto.com~/link_queue$ tree . ├── linklist.c ├── linklist.h ├── linkqueue.c ├── linkqueue.h └── main.c 0 directories, 5 files
链表实现实现文件:
chunli@http://990487026.blog.51cto.com~/link_queue$ cat linklist.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linklist.h"
typedef struct _tag_LinkList
{
//这个句柄里面,需要保存所有节点信息。需要有一个起始点
//就是带头节点的链表。。。
LinkListNode header;
int length;
}TLinkList;
LinkList* LinkList_Create()
{
TLinkList *ret = (TLinkList *)malloc(sizeof(TLinkList));
if (ret == NULL)
{
return NULL;
}
//memset(ret, 0, sizeof(TLinkList));
ret->header.next = NULL;
ret->length = 0;
return ret;
}
void LinkList_Destroy(LinkList* list)
{
if (list == NULL)
{
return ;
}
free(list);
return ;
}
void LinkList_Clear(LinkList* list)
{
TLinkList *tList =NULL;
if (list == NULL)
{
return ;
}
tList = (TLinkList *)list;
tList->length = 0;
tList->header.next = NULL;
return ;
}
int LinkList_Length(LinkList* list)
{
TLinkList *tList = (TLinkList *)list;
if (tList == NULL)
{
return -1;
}
return tList->length;
}
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos)
{
int i = 0;
TLinkList *tList = NULL;
LinkListNode *current = NULL;
tList = (TLinkList *)list;
if (list==NULL || node==NULL) //modify by bombing 2014.06.26
{
return -1;
}
//准备环境让辅助指针变量 指向链表头节点
current = &tList->header;
for (i=0; i<pos &&(current->next!=NULL); i++)
{
current = current->next;
}
//让node节点链接后续链表
node->next = current->next ;
//让前边的链表。链接node
current->next = node;
tList->length ++;
return 0;
}
LinkListNode* LinkList_Get(LinkList* list, int pos)
{
int i = 0;
TLinkList *tList = NULL;
LinkListNode *current = NULL;
LinkListNode *ret = NULL;
tList = (TLinkList *)list;
if (list == NULL || pos <0 ||pos>=tList->length)
{
return NULL;
}
//准备环境让辅助指针变量 指向链表头节点
current = &tList->header;
for (i=0; i<pos &&(current->next!=NULL); i++)
{
current = current->next;
}
ret = current->next;
return ret;
}
LinkListNode* LinkList_Delete(LinkList* list, int pos)
{
int i = 0;
TLinkList *tList = NULL;
LinkListNode *current = NULL;
LinkListNode *ret = NULL;
tList = (TLinkList *)list;
if (list == NULL || pos <0 ||pos>=tList->length)
{
return NULL;
}
//准备环境让辅助指针变量 指向链表头节点
current = &tList->header;
for (i=0; i<pos &&(current->next!=NULL); i++)
{
current = current->next;
}
ret = current->next;
//删除算法
current->next =ret->next;
tList->length--;
return ret;
}
chunli@http://990487026.blog.51cto.com~/link_queue$
链表函数声明文件:
chunli@http://990487026.blog.51cto.com~/link_queue$ cat linklist.h
#ifndef _MYLINKLIST_H_
#define _MYLINKLIST_H_
typedef void LinkList;
/*
typedef struct _tag_LinkListNode LinkListNode;
struct _tag_LinkListNode
{
LinkListNode* next;
};
*/
typedef struct _tag_LinkListNode
{
struct _tag_LinkListNode* next;
}LinkListNode;
LinkList* LinkList_Create();
void LinkList_Destroy(LinkList* list);
void LinkList_Clear(LinkList* list);
int LinkList_Length(LinkList* list);
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos);
LinkListNode* LinkList_Get(LinkList* list, int pos);
LinkListNode* LinkList_Delete(LinkList* list, int pos);
#endif
chunli@http://990487026.blog.51cto.com~/link_queue$
队列的实现文件:
chunli@http://990487026.blog.51cto.com~/link_queue$ cat linkqueue.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "linkqueue.h"
#include "linklist.h"
typedef struct _tag_LinkQueueNode
{
LinkListNode node;
void *item;
}TLinkQueueNode;
//思想:用线性表来模拟队列
//创建一个队列,相当于创建一个线性表
LinkQueue* LinkQueue_Create() //O(1)
{
return LinkList_Create();
}
void LinkQueue_Destroy(LinkQueue* queue) //O(1)
{
LinkQueue_Clear(queue);
LinkList_Destroy(queue);
return ;
}
void LinkQueue_Clear(LinkQueue* queue) //O(n)
{
while (LinkQueue_Length(queue) > 0)
{
LinkQueue_Retrieve(queue);
}
//LinkQueue_Clear(queue);
return ;
}
//向队列中添加元素,相当于向队列的尾部插入元素
int LinkQueue_Append(LinkQueue* queue, void* item) //O(n)
{
int ret = 0;
TLinkQueueNode *node = NULL;
//需要向linklist中添加业务节点,需要在业务节点中包含链表结点
//需要让链表结点放在业务节点的第一个成员域。
//把形参item,转换为 linklist识别的业务节点
node = (TLinkQueueNode *)malloc(sizeof(TLinkQueueNode));
if (node == NULL)
{
return -1;
}
memset(node, 0, sizeof(TLinkQueueNode));
node->item = item;
ret = LinkList_Insert(queue, (LinkListNode *)node, LinkList_Length(queue));
if (ret != 0)
{
free(node);
return ret;
}
return ret;
}
//从队列删除元素,相当于从队列的头部拿元素
void* LinkQueue_Retrieve(LinkQueue* queue) //O(1)
{
void *item = NULL;
TLinkQueueNode *node = NULL;
//需要向linklist中添加业务节点,需要在业务节点中包含链表结点
node = (TLinkQueueNode *)LinkList_Delete(queue, 0);
if (node == NULL)
{
return NULL;
}
item = node->item;
if (node != NULL)
{
free(node);
node = NULL;
}
return item;
}
//获取队列头元素,相当于从队列0位置拿元素
void* LinkQueue_Header(LinkQueue* queue) //O(1)
{
void *item = NULL;
TLinkQueueNode *node = NULL;
node = (TLinkQueueNode *)LinkList_Get(queue, 0);
if (node == NULL)
{
return NULL;
}
item = node->item;
return item;
}
int LinkQueue_Length(LinkQueue* queue)
{
return LinkList_Length(queue);
}
chunli@http://990487026.blog.51cto.com~/link_queue$
队列的申明文件:
chunli@http://990487026.blog.51cto.com~/link_queue$ cat linkqueue.h
#ifndef _MY_LINKQUEUE_H_
#define _MY_LINKQUEUE_H_
typedef void LinkQueue;
LinkQueue* LinkQueue_Create();
void LinkQueue_Destroy(LinkQueue* queue);
void LinkQueue_Clear(LinkQueue* queue);
int LinkQueue_Append(LinkQueue* queue, void* item);
void* LinkQueue_Retrieve(LinkQueue* queue);
void* LinkQueue_Header(LinkQueue* queue);
int LinkQueue_Length(LinkQueue* queue);
#endif //_MY_LINKQUEUE_H_
chunli@http://990487026.blog.51cto.com~/link_queue$
主函数:
chunli@http://990487026.blog.51cto.com~/link_queue$ cat main.c
// chunli@http://990487026.blog.51cto.com~/link_queue$ gcc main.c linklist.c linkqueue.c -Wall && ./a.out
// 队列的长度:20
// 队头元素:1
// 出列:1
// 出列:3
// 出列:7
// 出列:13
// 出列:21
// 出列:31
// 出列:43
// 出列:57
// 出列:73
// 出列:91
// 出列:111
// 出列:133
// 出列:157
// 出列:183
// 出列:211
// 出列:241
// 出列:273
// 出列:307
// 出列:343
// 出列:381
// chunli@http://990487026.blog.51cto.com~/link_queue$
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linkqueue.h"
#define MAX 20
int main()
{
int i = 0;
int a[MAX] = {0};
//创建队列
LinkQueue *queue = LinkQueue_Create();
if(queue == NULL)
{
printf("error in LinkQueue_Create()\n");
return -1;
}
//入队列
for(i=0;i<MAX;i++)
{
a[i] = i*i+i+1;
LinkQueue_Append(queue,&a[i]);
}
//求队列的属性
printf("队列的长度:%d\n",LinkQueue_Length(queue));
printf("队头元素:%d\n",*(int*)LinkQueue_Header(queue));
//出列
while(LinkQueue_Length(queue) > 0)
{
printf("出列:%d\n",*(int*)LinkQueue_Header(queue));
LinkQueue_Retrieve(queue);
}
//销毁队列
LinkQueue_Destroy(queue);
return 0;
}
chunli@http://990487026.blog.51cto.com~/link_queue$
编译运行:
chunli@http://990487026.blog.51cto.com~/link_queue$ gcc -Wall main.c linklist.c linkqueue.c &&./a.out 队列的长度:20 队头元素:1 出列:1 出列:3 出列:7 出列:13 出列:21 出列:31 出列:43 出列:57 出列:73 出列:91 出列:111 出列:133 出列:157 出列:183 出列:211 出列:241 出列:273 出列:307 出列:343 出列:381 chunli@http://990487026.blog.51cto.com~/link_queue$
转载于:https://blog.51cto.com/990487026/1851732