栈与队列都是具有特殊存取方式的线性表,栈属于先进后出(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. ubuntu:好用的help命令

    以前光知道如何不清楚某个命令的用法可以打上后缀 ‘ --help' 现在刚发现,原来还有help命令来帮忙,如果你安装的是中文支持,在ubuntu上, 那么部分命令说明还是中文版哦. 举例: help ...

  2. JDK1.9-新特性

    1. Java平台级模块系统 该特性使Java9最大的一个特性,Java提供该功能的主要的动机在于,减少内存的开销,JVM启动的时候,至少会有30~60MB的内存加载,主要原因是JVM需要加载rt.j ...

  3. atitit.js的 字符串内容 转义  js处理html

    atitit.js的 字符串内容 转义  js处理html 1. js处理html的问题 1 2. js的 字符串内容 转义 1 2.1. 处理流程 1 3. 下面的表格列出了其余的特殊字符,这些特殊 ...

  4. tensorflow 之模型的保存与加载(一)

    怎样让通过训练的神经网络模型得以复用? 本文先介绍简单的模型保存与加载的方法,后续文章再慢慢深入解读. #!/usr/bin/env python3 #-*- coding:utf-8 -*- ### ...

  5. windows下安装C语言环境

    安装 1.下载 min-gw 安装程序,链接为:http://sourceforge.net/projects/mingw/files/,下载 Download mingw-get-setup.exe ...

  6. 基于jQuery的让非HTML5浏览器支持placeholder属性的代码(转)

    效果图:http://code.google.com/p/jquery-placeholder-js/ 演示代码:http://demo.jb51.net/js/2011/jqueryplacehol ...

  7. iReport4.6.0图表操作

    做报表.图表肯定是少不了的.尽管是疲惫的周一工作还是要做啊... 第一步:创建一个新的空白项目,数据源创建这个网上非常多资料,不是本章重点就不再详述 第二步:iReport界面,窗体->组件面板 ...

  8. 后台运行 screen命令

    nohub不能用的,用这个 后台运行 yum install screen 只要Screen本身没有终止,在其内部运行的会话都可以恢复 登录到主机上执行screen -r就可以恢复会话的运行. 同样在 ...

  9. python 的简单抓取图片

    在我们日常上网浏览网页的时候,经常会看到一些好看的图片,我们就希望把这些图片保存下载,或者用户用来做桌面壁纸,或者用来做设计的素材. 我们最常规的做法就是通过鼠标右键,选择另存为.但有些图片鼠标右键的 ...

  10. oracle的dual表

    1.DUAL表的用途Dual 是 Oracle中的一个实际存在的表,任何用户均可读取,常用在没有目标表的Select语句块中 --查看当前连接用户Connected to Oracle Databas ...