栈与队列都是具有特殊存取方式的线性表,栈属于先进后出(FILO),而队列则是先进先出(FIFO)。栈能够将递归问题转化为非递归问题,这是它的一个重要特性。除了FILO、FIFO这样的最普遍存取方式外,还有一些扩展的数据结构,如双端队列、双栈、超队列、超栈等,它们是一种扩展与变异结构。

  线性表有顺序存储和链接存储两类,这是针对计算机的线性存储空间作出的分类。前者可以是数组,后者可以是链表。字符串是线性表最常见的应用。

  这里我用C语言实现了一个基于数组环形队列,它具有固定的队列空间。相比于链表实现,它非常小巧和高效,特别是在负载可预计的情况下。

//fifo.h
#ifndef __FIFO_H__
#define __FIFO_H__ #define FIFO_LENGTH 20
#define EMPTY 0x00
#define FULL 0x01
#define NORMAL 0x02 typedef struct require_fifo{
int item[FIFO_LENGTH];
int read_ptr;
int write_ptr;
int flag;
}fifo; extern fifo* fifo_create(void);
extern void fifo_destroy(fifo* fifo_ptr);
extern void fifo_in(fifo* fifo_ptr, int data);
extern int fifo_out(fifo* fifo_ptr); #endif
//fifo.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <memory.h>
#include "fifo.h" fifo* fifo_create(void);
void fifo_destroy(fifo* fifo_ptr);
void fifo_in(fifo* fifo_ptr, int data);
int fifo_out(fifo* fifo_ptr); fifo* fifo_create(void){
fifo *fifo_ptr = malloc(sizeof(fifo));
memset(fifo_ptr, , sizeof(fifo));
fifo_ptr->write_ptr = ;
fifo_ptr->read_ptr = ;
fifo_ptr->flag = EMPTY;
return fifo_ptr;
} void fifo_destroy(fifo* fifo_ptr){
free(fifo_ptr);
printf("destroy fifo \n");
} void fifo_in(fifo* fifo_ptr, int data){
if(fifo_ptr->flag != FULL ){
fifo_ptr->item[fifo_ptr->write_ptr] = data;
fifo_ptr->write_ptr ++;
fifo_ptr->write_ptr %= FIFO_LENGTH;
if((fifo_ptr->write_ptr - fifo_ptr->read_ptr) == -){
fifo_ptr->flag = FULL;
}else{
fifo_ptr->flag = NORMAL;
}
//printf("write_ptr = %d \n", fifo_ptr->write_ptr);
}else{
printf("fifo is full, write invalide\n");
}
} int fifo_out(fifo* fifo_ptr){
int data = ; if(fifo_ptr->flag != EMPTY){
data = fifo_ptr->item[fifo_ptr->read_ptr];
fifo_ptr->read_ptr ++;
fifo_ptr->read_ptr %= FIFO_LENGTH;
if((fifo_ptr->write_ptr - fifo_ptr->read_ptr) == ){
fifo_ptr->flag = EMPTY;
}
//printf("read_ptr = %d \n", fifo_ptr->read_ptr);
return data;
}else{
printf("fifo is empty, read invalide\n");
return -;
} return -;
}

  我们可以写一个测试代码来测试它的性能:

#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include "../fifo.h" pthread_mutex_t lock_fifo;
fifo* myfifo; void * producer_thread1(void *pin){
pin = NULL;
while(){
pthread_mutex_lock(&lock_fifo);
fifo_in(myfifo, );
pthread_mutex_unlock(&lock_fifo);
printf("producer1 put 1 into myfifo\n");
usleep();
}
return((void*));
} void * producer_thread2(void *pin){
pin = NULL;
while(){
pthread_mutex_lock(&lock_fifo);
fifo_in(myfifo, );
pthread_mutex_unlock(&lock_fifo);
printf("producer2 put 2 into myfifo\n");
usleep();
}
return((void*));
} void * consumer_thread1(void *pin){
int require = ;
pin = NULL; while(){
pthread_mutex_lock(&lock_fifo);
require = fifo_out(myfifo);
pthread_mutex_unlock(&lock_fifo);
printf(" consumer1 get %d form myfifo\n", require);
usleep();
}
return((void*));
} void * consumer_thread2(void *pin){
int require = ;
pin = NULL; while(){
pthread_mutex_lock(&lock_fifo);
require = fifo_out(myfifo);
pthread_mutex_unlock(&lock_fifo);
printf(" consumer2 get %d form myfifo\n", require);
usleep();
}
return((void*));
} void keyboard_exit(int signo){
printf("exit by keyboard \n");
fifo_destroy(myfifo);
_exit();
} int main(){
pthread_t th_producer1, th_producer2, th_consumer1, th_consumer2;
void * ret; pthread_mutex_init(&lock_fifo, NULL);
myfifo = fifo_create();
signal(SIGINT, keyboard_exit);
pthread_create(&th_producer1, NULL, producer_thread1, );
pthread_create(&th_producer2, NULL, producer_thread2, );
pthread_create(&th_consumer1, NULL, consumer_thread1, );
pthread_create(&th_consumer2, NULL, consumer_thread2, ); pthread_join(th_producer1, &ret);
pthread_join(th_producer2, &ret);
pthread_join(th_consumer1, &ret);
pthread_join(th_consumer2, &ret); while(){
printf("thread error\n");
}
return ;
}

  写一个gcc的Makefile文件来编译链接:

CC = gcc
CFLAGS := -g -Wall
LIB := -lpthread
OBJ = ../fifo.o ./test.o
all: demo demo:test fifo
$(CC) $(CFLAGS) -o ./demo $(OBJ) $(LIB) test:
$(CC) $(CFLAGS) -o ./test.o -c ./test.c
fifo:
$(CC) $(CFLAGS) -o ../fifo.o -c ../fifo.c clean:
rm ./test.o ./demo ../fifo.o .PHONY: $(PHONY) clean

  在test目录下运行./demo。

  输出结果:

                            write_ptr =
producer1 put into myfifo
write_ptr =
producer2 put into myfifo
read_ptr =
consumer1 get form myfifo
read_ptr =
consumer2 get form myfifo
fifo is empty, read invalide
consumer1 get - form myfifo
fifo is empty, read invalide
consumer2 get - form myfifo
write_ptr =
producer2 put into myfifo
write_ptr =
producer1 put into myfifo
read_ptr =
consumer1 get form myfifo
read_ptr =
consumer2 get form myfifo
write_ptr =
producer2 put into myfifo
read_ptr =
。。。。
。。。。
^Cexit by keyboard
destroy fifo

<2014 05 16> 线性表、栈与队列——一个环形队列的C语言实现的更多相关文章

  1. [置顶] ※数据结构※→☆线性表结构(queue)☆============循环队列 顺序存储结构(queue circular sequence)(十)

    循环队列 为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量.存储在其中的队列称为循环队列(Circular Queue). ...

  2. k:特殊的线性表—栈

    栈(Stack):  栈是一种特殊的线性表,栈中的数据元素以及数据元素之间的逻辑关系和线性表相同,两者之间的差别在于:线性表的插入和删除操作可以在表的任意位置进行,而栈的插入和删除操作只允许在表的尾端 ...

  3. 数据结构-线性表的链式存储相关算法(C语言实现)

    链表的简单介绍 为什么需要线性链表 当然是为了克服顺序表的缺点,在顺序表中,做插入和删除操作时,需要大量的移动元素,导致效率下降. 线性链表的分类 按照链接方式: 按照实现角度: 线性链表的创建和简单 ...

  4. 队列(Queue)--环形队列、优先队列和双向队列

    1. 队列概述 队列和堆栈都是有序列表,属于抽象型数据类型(ADT),所有加入和删除的动作都发生在不同的两端,并符合First In, First Out(先进先出)的特性. 特性: ·FIFO ·拥 ...

  5. Java 单向队列及环形队列

    队列的特点 1.可以使用数组和链表两种方式来实现. 2.遵循先入先出(FIFO)的规则,即先进入的数据先出. 3.属于有序列表. 图解实现过程: ​ 1.定义一个固定长度的数组,长度为maxSize. ...

  6. c# 写着玩的,两个Task并发,一个写队列一个读队列的异常情况

    class Program { class TestEnqueue { static Queue<string> str = new Queue<string>(); publ ...

  7. Java数据结构之线性表(2)

    从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...

  8. java线性表学习笔记(一)

    线性表是一种按顺序储存数据是的常用结构,大多数的线性表都支持以下的典型操作: 从线性表提取插入删除一个数据: 找出线性表中的某一个元素: 找出线性表中的元素: 确定线性表中是否包含某一个元素,确定线性 ...

  9. 线性表结构的Java实现

    一.线性表的抽象数据类型表述 线性表的结构简单,长度允许动态增长或搜索:可以对线性表中的任何数据元素进行访问和查找:允许进行数据的插入和删除操作:求线性表中的指定数据的前驱和后继:合并线性表以及拆分线 ...

随机推荐

  1. Hadoop-2.4.0分布式安装手冊

    文件夹 文件夹 1 1. 前言 2 2. 部署 2 2.1. 机器列表 2 2.2. 主机名 2 2.2.1. 暂时改动主机名 3 2.2.2. 永久改动主机名 3 2.3. 免password登录范 ...

  2. ArcGIS教程:Geostatistical Analyst 应用演示样例

    Geostatistical Analyst 满足多种不同应用的需求. 下面是 Geostatistical Analyst 的一小部分应用演示样例. 探索性空间数据分析 Geostatistical ...

  3. Java遍历包中所有类

    PackageUtil 类 import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java. ...

  4. 基于numpy的随机数构造

    class numpy.random.RandomState(seed=None) RandomState 是一个基于Mersenne Twister算法的伪随机数生成类 RandomState 包含 ...

  5. ECMall中Widgets模式的布局引擎

    自己做过框架的人,可能都会思考一个问题,模板引擎需要什么特性? Widgets模式,很多系统中都有出现,但对于纯开发人员,不管前端或后台人员来说,都觉得稍微麻烦了一点.因为他将界面硬生生的拆分出了很多 ...

  6. jquery Ajax Queue 队列实现

    有时候我们需要按顺序调用一组ajax,这些ajax需要有先后顺序,类似于同步的ajax,那么我们可以通过以下的方式来实现: (这个Ajax用到jQuery.post) //定义一个AJAX队列 $.n ...

  7. 可执行文件格式elf和bin

    区别 常用的可执行文件包含两类:原始二进制文件(bin)和可加载执行的二进制文件,在linux中可加载执行的二进制文件为elf文件. BIN文件是直接的二进制文件,内部没有地址标记.bin文件内部数据 ...

  8. android studio 中配置androidAnnotation 的新版正确配置

    apply ].processResources.manifestFile resourcePackageName 'com.peiandsky.firstandroidstudio' }}

  9. 手把手教你Chrome扩展开发:本地存储篇

    手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩展二:为html添加行为 手把手教你开发Chrome扩展三:关于本地存储数据 HTML5 ...

  10. confirg

     如果用户点击确定按钮,则 confirm() 返回 true.如果点击取消按钮,则 confirm() 返回 false.在用户点击确定按钮或取消按钮把对话框关闭之前,它将阻止用户对浏览器的所有输入 ...