2016-04-15 17:09:21 Lina_ACM 阅读数 2467
  • input子系统基础之按键-linux驱动开发第8部分

    本课程是linux驱动开发的第8个课程,主要内容是linux的input子系统。学习本课程的目标是对input子系统的框架结构有深入理解,应用层和驱动层的调用关系和方法完全了解,能够自己移植按键等常见输入类设备的驱动。

    5164 人正在学习 去看看 朱有鹏
#include<stdio.h>
#include<stdlib.h>
#define N sizeof(stacknode)//结点所占字节数 N

//定义结构体
typedef int datatype;
typedef struct stacknode
{
	datatype data;
	struct stacknode *next;
}stacknode;

//定义栈顶
typedef struct 
{
	stacknode *top;
	int count;//计数用
}linkstack;


//进栈,元素一一进栈
void InsertStack(linkstack *s)
{

	int x=0;
	stacknode *p;
	s->top=NULL;
	s->count=0;
	//printf("\n\t建立一个栈子系统");
	p=(stacknode*)malloc(N);
	printf("\n\t\t请逐个输入数字,结束标记位,做结束符的数字: 0     \n");
	while(1)
	{
		/*printf("\t\t请输入:");
		fflush(stdin);
		
		if(!scanf("%d",&x))
		{
			printf("输入的元素种类错误!!!\n");
			continue;
		}
		else if(x=='#') break;
		else
		{
			p->data=x;
			p->next=s->top;
			s->top=p;
			s->count++;
		}
		*/
		printf("\t\t请输入:");
		p=(stacknode*)malloc(N);
		fflush(stdin);
		if(!scanf("%d",&x))
		{
			printf("\t\t\t输入的“元素“种类错误!!!\n");
			continue;
		}
		else if(x==0)
			break;
		else
		{
			
			p->data=x;
			p->next=s->top;
			s->top=p;
			s->count++;
		}
	}
	printf("\n");
	
}


//显示栈中元素
void ShowStack(linkstack *s)
{
	stacknode *p;
	int i=0;
	p=s->top;
	i=s->count;
	//p->data=s->top->data;
	//if(p->next==NULL)
	if(i==0)
	printf("\t\t栈是一个空栈!!!!\n");
	else
	{
		printf("\t栈中各个元素为:\t");
		while(i!=0)
		{
			printf("%8d",p->data);
			p=p->next;
			//s->top=s->top->next;
			i--;
		}
	}
	printf("\n");
}


//求栈中元素的个数
void LengthStack(linkstack *s)
{
	printf("\t栈中元素的个数为:\t");
	printf("%d",s->count);
}


//出栈,栈中各个元素的出栈
void PutStack(linkstack *s)
{
	//int x;
	stacknode *p;
	//linkstack *i;
	if(s->count==0)
	{
		printf("\t\t栈是一个空栈!!!!");
	//	return 0;
	}
	else
	{
		/*
		p=s->top;
		x=p->data;
		s->top=p->next;
		free(p);
		//s->count-=1;
		*/
		p=s->top;
		s->top=s->top->next;
		printf("\n\t\t\t\t出栈元素为:		%d\n",p->data);
		free(p);
		s->count--;
	}
}


//数制转换,十进制转换为二进制
void ShiftStack(linkstack *s)
{
	int z=0;
	int m=0;
	stacknode *p;
	printf("请输入所要转换的 ”数字“ Z:\t");
	scanf("%d",&z);
	s->top=NULL;
	while(z)
	{
		m=z%2;
		z=z/2;
		p=(stacknode*)malloc(N);
		p->next=s->top;
		s->top=p;
		s->top->data=m;
	}
	printf("\n\t转化后的二进制为\t");
	while(s->top)
	{
		p=s->top;
		printf("%d",p->data);
		s->top=s->top->next;
		free(p);
	}
	printf("\n");		
}




int main()
{
	int a;
	linkstack s;
	s.count=0;
	//linkstack *s;
	while(1)
    {
		printf("                        \n\t\t\t\t\t\t栈子系统\n");
		printf("            \t\t***************************************************\n");
		printf("            \t\t*               1------进    栈                   *\n");
		printf("            \t\t*               2------出    栈                   *\n");
		printf("            \t\t*               3------显示栈中元素               *\n");
		printf("            \t\t*               4------求栈中元素个数             *\n");
		printf("            \t\t*               5------数制转换                   *\n");
		printf("            \t\t*               0------返    回                   *\n");
		printf("            \t\t***************************************************\n");
		printf("            请输入(0-5)选项:\n");
        printf("\n请输入所要达到第几号功能:\t");
		fflush(stdin);
		scanf("%d",&a);
        if(a == 1)
            InsertStack(&s);
        else if(a == 2)
            PutStack(&s);
        else if(a == 3)
            ShowStack(&s);
        else if(a == 4)
           LengthStack(&s);
        else if(a == 5)
            ShiftStack(&s);
        else if(a == 0)
            return 0;
        else{
            printf("!!!!!输入有误,请重新输入!!!!!\n"); 
	}
 } 
}

2019-08-24 16:20:05 m0_38051293 阅读数 77
  • input子系统基础之按键-linux驱动开发第8部分

    本课程是linux驱动开发的第8个课程,主要内容是linux的input子系统。学习本课程的目标是对input子系统的框架结构有深入理解,应用层和驱动层的调用关系和方法完全了解,能够自己移植按键等常见输入类设备的驱动。

    5164 人正在学习 去看看 朱有鹏

栈 Stack

  1. 栈是一种线性结构
  2. 相比数组,栈对应的操作是数组的子集
  3. 只能从一端添加元素,也只能从同一端取出元素(添加删除都在栈顶执行)
  4. 栈是一种后进先出的数据结构

栈的应用

无处不在的Undo操作(撤销操作)
程序调用的系统栈(子过程子逻辑调用的机理递归调用)
括号匹配-编译器

栈的实现

以java为例

Stack<E>
void push (e)
E pop()      
E peek()    
int getSize()
boolean isEmpty() 

栈顶元素反映了在嵌套的层次关系中,最近的需要匹配的元素

//栈的应用在字符匹配上这是leetcode中的一道题,借鉴了别人的代码
import java.util.Stack;
class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i = 0 ; i < s.length() ; i ++){
            char c = s.charAt(i);
            if(c == '(' || c == '[' || c == '{')
                stack.push(c);
            else{
                if(stack.isEmpty())
                    return false;
                char topChar = stack.pop();
                if(c == ')' && topChar != '(')
                    return false;
                if(c == ']' && topChar != '[')
                    return false;
                if(c == '}' && topChar != '{')
                    return false;
            }
        }
        return stack.isEmpty();

队列 Queue

  1. 队列是一种线性结构
  2. 相比数组,队列对应的操作是数组的子集
  3. 只能从队尾添加元素,也只能从队首取出元素
  4. 队列是一种先进先出的数据结构(先到先得)

队列的实现

Queue<E> 
    int getSize();
    boolean isEmpty();
    void enqueue(E e);
    E dequeue();
    E getFront();

数组队列与循环队列

font = = tail 队列为空 tail+1==front 队列满
在这里插入图片描述
循环队列比数组队列更节约时间。

2019-04-02 22:30:42 l0919160205 阅读数 42
  • input子系统基础之按键-linux驱动开发第8部分

    本课程是linux驱动开发的第8个课程,主要内容是linux的input子系统。学习本课程的目标是对input子系统的框架结构有深入理解,应用层和驱动层的调用关系和方法完全了解,能够自己移植按键等常见输入类设备的驱动。

    5164 人正在学习 去看看 朱有鹏

一、栈

栈是一种线性结构,栈对应的操作是数组的子集;栈只能从一端添加元素,也只能从一端取出元素,这一端称为栈顶,是一种后进先出的数据结构。

栈的一些常见的应用有undo操作(撤销)、程序调用的系统栈(程序中断时进入系统栈,当子过程执行完成后,通过系统栈回到上层中断的位置继续执行)。

因为栈对应的操作是数组的子集,所以直接使用上一节数据结构----数组(java实现代码)的删除元素和添加元素的功能即可。具体实现代码如下:

创建一个栈的接口:

package com.lxr.stack0331;

public interface Stack<E> {

	int getSize();//复杂度o(1)
	boolean isEmpty();//复杂度o(1)
	void push(E e);//复杂度o(1),均摊
	E pop();//复杂度o(1),均摊
	E peek();//复杂度o(1)
}

ArryayStack.java实现代码:

package com.lxr.stack0331;

import com.lxr.array0330.Array;

public class ArryayStack<E> implements Stack<E>{

	Array<E> array;
	
	public ArryayStack(int capacity) {
		// TODO Auto-generated constructor stub
		array=new Array<>(capacity);
	}
	
	public ArryayStack() {
		// TODO Auto-generated constructor stub
		array=new Array<>();
	}
	
	@Override
	public int getSize() {
		
		return array.getsize();
	}

	@Override
	public boolean isEmpty() {
		
		return array.isEmpty();
	}

	@Override
	public void push(E e) {
		array.addElement(e);
		
	}

	@Override
	public E pop() {
		return array.delateLast();
	}

	@Override
	public E peek() {
		return array.getLast();
	}

	public int getCapacity() {
		return array.getCapacity();
	}
	
	@Override
	public String toString() {
		StringBuilder reStringBuilder =new StringBuilder();
		reStringBuilder.append(String.format("Stack"));
		reStringBuilder.append('[');
		for(int i=0;i<array.getsize();i++) {
		    reStringBuilder.append(array.get(i));
		    if(i!=array.getsize()-1)
		    	reStringBuilder.append(", ");
		}
		reStringBuilder.append("] top");
		
		return reStringBuilder.toString();
	}
}

栈的应用例举-------leetcode20(匹配括号)
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:

输入: "()"
输出: true

示例 2:

输入: "()[]{}"
输出: true

示例 3:

输入: "(]"
输出: false

示例 4:

输入: "([)]"
输出: false

示例 5:

输入: "{[]}"
输出: true

分析:即当字符为左括弧时即“(、{、【”时则入栈,当字符为右括弧时判断栈顶字符是否匹配,如果匹配则出栈,否则返回false,代码如下:

   public class Solution {
    
        public boolean isValid(String s) {
            Stack<Character> stack=new Stack<>();
            for(int i=0;i<s.length();i++) {
            	char c=s.charAt(i);
            	if(c=='('||c=='{'||c=='[') {
            		stack.push(c);
            	}else {
            		if(stack.isEmpty())
            			return false;
            		char topChar=stack.pop();
            		if(c==')'&&topChar!='('||c=='}'&&topChar!='{'||c==']'&&topChar!='[') 
            			return false;
            	}
            }
            
            return stack.isEmpty();
        }
        
    }

二、队列

队列也是一种线性结构,相比数组,队列对应的操作是数组的子集,智能从一端(队尾)添加元素,只能从另一端(队首)取出元素,队列是一种先进先出的数据结构(FIFO)
1.数组队列
数组队列出队的时间复杂度是o(n),因为数组删除第一个元素的时间复杂度是o(n),因为数组队列对应的操作也是数组的子集,所以直接使用上一节数据结构----数组(java实现代码)的删除元素和添加元素的功能即可。具体实现代码如下:

创建一个数组队列的接口:

package com.lxr.Queue0402;

public interface Queue <E>{
	int getSize();//复杂度o(1)均摊
	boolean isEmpty();//复杂度o(1)
	void enqueue(E e);//复杂度o(1)
	E dequeue();//复杂度o(n)
	E getFrount();//复杂度o(1)
}

ArrayQueue.java代码:

package com.lxr.Queue0402;

import com.lxr.array0330.Array;

public class ArrayQueue<E> implements Queue<E>{

	private Array<E> array;
	
	public ArrayQueue(int capacity) {
		array=new Array<>(capacity);
	}
	
	public ArrayQueue() {
		array=new Array<>();
	}
	
	@Override
	public int getSize() {
		// TODO Auto-generated method stub
		return array.getsize();
	}

	@Override
	public boolean isEmpty() {
		// TODO Auto-generated method stub
		return array.isEmpty();
	}

	@Override
	public void enqueue(E e) {
		// TODO Auto-generated method stub
		array.addElement(e);
		
	}

	@Override
	public E dequeue() {
		// TODO Auto-generated method stub
		return array.delateFrist();
	}

	@Override
	public E getFrount() {
		// TODO Auto-generated method stub
		return array.getFirst();
	}
	
	public int getCapacity() {
		return array.getCapacity();
	}
	
	@Override
	public String toString() {
		StringBuilder reStringBuilder =new StringBuilder();
		reStringBuilder.append("Queue ");
		reStringBuilder.append("front[");
		for(int i=0;i<array.getsize();i++) {
		    reStringBuilder.append(array.get(i));
		    if(i!=array.getsize()-1)
		    	reStringBuilder.append(", ");
		}
		reStringBuilder.append("] tail");
		
		return reStringBuilder.toString();
	}
	
	public static void main(String[] args) {
		//测试
		ArrayQueue<Integer> arrayQueue=new ArrayQueue<>(20);
		for(int i=0;i<20;i++) {
			arrayQueue.enqueue(i);
			if(i%3==2) {
				arrayQueue.dequeue();
			}
			System.out.println(arrayQueue);
		}
	}
	
}

2.循环队列
为解决数列数组出队时时间复杂度为O(n),引出了循环队列。循环队列中有front和tail,front指向第一个元素,tail指向最后一个元素的后一个元素,frount==tail是队列为空,当(tail+1)%c ==front(c为队列长度)时表示队列已满,有意识的浪费了一个空间,这块空间是由tail指向。
在这里插入图片描述
循环队列的动态扩容是从front指向的元素开始复制到新的数组中,改变front,tail,size的值。

创建一个循环队列的接口:

package com.lxr.Queue0402;

public interface Queue <E>{
	int getSize();//复杂度o(1)均摊
	boolean isEmpty();//复杂度o(1)
	void enqueue(E e);//复杂度o(1)
	E dequeue();//复杂度o(1),均摊
	E getFrount();//复杂度o(1)
}

LoopQueue.java代码:

package com.lxr.Queue0402;

import java.awt.Font;

public class LoopQueue<E> implements Queue<E>{
	
	private E[] data;
	private int front,tail;
	private int size;
	
	public LoopQueue(int capacity) {
		// TODO Auto-generated constructor stub
		data=(E[])new Object[capacity+1];
		front=0;
		tail=0;
		size=0;
	}
	
	//初始容量为10
	public LoopQueue() {
		this(10);
	}
	
	public int getCapacity() {
		return data.length-1;
	}

	@Override
	public int getSize() {
		return size;
	}

	@Override
	public boolean isEmpty() {
		return front==tail;
	}

	//队列添加元素
	@Override
	public void enqueue(E e) {
		//如果队列已满,动态添加队列长度,使用getCapacity()避免多浪费一个空间
		if((tail+1)%data.length==front) {
			resize(getCapacity()*2);
		}
		
		data[tail]=e;
		tail=(tail+1)%data.length;
		size++;
		
	}

	//动态添加空间
	private void resize(int i) {
		E[] newdata=(E[])new Object[i+1];
		//第一种遍历队列的方式
		for (int j = 0; j < size; j++) {
			newdata[j]=data[(j+front)%data.length];
		}
		data=newdata;
		front=0;
		tail=size;
		
	}

	//出队操作
	@Override
	public E dequeue() {
		
		if(isEmpty())
			throw new IllegalArgumentException("队列为空");
		E a=data[front];
		data[front]=null;
		front=(front+1)%data.length;
		size--;
		//动态缩容
		if(size==getCapacity()/4&&getCapacity()/2!=0)
			resize(getCapacity()/2);
		return a;
	}

	//返回第一个元素
	@Override
	public E getFrount() {
		if(isEmpty())
			throw new IllegalArgumentException("队列为空");
		
		return data[front];
	}
	
	@Override
	public String toString() {
		StringBuilder reStringBuilder =new StringBuilder();
		reStringBuilder.append(String.format("Queue:size=%d,capacity=%d\n",size,getCapacity()));
		reStringBuilder.append("front [");
		//第二种遍历队列的方式
		for(int i=front;i!=tail;i=(i+1)%data.length) {
		    reStringBuilder.append(data[i]);
		    if((i+1)%data.length!=tail)
		    	reStringBuilder.append(", ");
		}
		reStringBuilder.append("] tail");
		
		return reStringBuilder.toString();
	}
	
	public static void main(String[] args) {
		//测试
		LoopQueue<Integer> loopQueue=new LoopQueue<>(10);
		for(int i=0;i<20;i++) {
			loopQueue.enqueue(i);
			if(i%3==2) {
				loopQueue.dequeue();
			}
			System.out.println(loopQueue);
		}
	}
}

3.数组队列和循环队列比较
数组队列和循环队列的复杂度的区别主要是在出队时,通过相同次数的入队出队操作后所需要的时间来比较数组队列和循环队列的效率。
测试代码:

package com.lxr.Queue0402;

import java.util.Random;

public class Main {

	public static double test(Queue<Integer> q,int num) {
		//开始时间计时
		long startTime=System.nanoTime();
		
		//进行num次入队和出队的操作
		Random random=new Random();
		for(int i=0;i<num;i++)
			q.enqueue(random.nextInt(Integer.MAX_VALUE));
		for(int i=0;i<num;i++)
			q.dequeue();
		
		//结束时间计时
		long endTime=System.nanoTime();
		
		return (endTime-startTime)/1000000000.0;
	}
	
	public static void main(String[] args) {
		int num=100000;
		
		ArrayQueue<Integer> arrayQueue=new ArrayQueue<Integer>();
		double time1=test(arrayQueue, num);
		System.out.println("ArrayQueue,time: "+time1+" s");
		
		LoopQueue<Integer> loopQueue=new LoopQueue<Integer>();
		double time2=test(loopQueue, num);
		System.out.println("LoopQueue,time: "+time2+" s");
	}

}

测试结果:

在这里插入图片描述
可以看出数组队列明显比循环队列用时时间长。不同的JMV或电脑运行的时间可能会有所不同。

2016-09-13 11:53:16 u014532901 阅读数 7093
  • input子系统基础之按键-linux驱动开发第8部分

    本课程是linux驱动开发的第8个课程,主要内容是linux的input子系统。学习本课程的目标是对input子系统的框架结构有深入理解,应用层和驱动层的调用关系和方法完全了解,能够自己移植按键等常见输入类设备的驱动。

    5164 人正在学习 去看看 朱有鹏

常用数据结构栈的应用—-表达式求值

栈是常用的数据结构,栈又称堆栈,是一种受限的线性表。其限制是允许在表中的一端进行插入和删除元素。栈中的元素符合后进先出(FILO)的性质。允许插入和删除元素的一端被称为栈顶,另一端被称为栈底。
栈有两种关键的操作,分别为出栈和压栈。

栈有两种关键的操作,分别为出栈和压栈。

  • 出栈(pop):它是把栈顶的元素E删除,使E的下一个元素称为新的栈顶,并返回元素E
  • 压栈(push):它是将元素E插入栈顶,使得新插入的元素E称为新的栈顶。

栈的常见的应用主要有:编译器中语法分析的符号匹配、表达式求值、程序的函数调用等。
例如:操作系统中的进程的上下文切换,里面被切换下CPU的进程的现场信息例如寄存器等信息,被保存在堆栈中,等到CPU轮转到该进程时,使用堆栈恢复现场。

表达式求值

表达式求值是栈的一个重要的应用。例如计算器中的加减乘除表达式的计算,都会使用栈来进行求值。
表达式的表示方法主要有中缀表示法和后缀表示法。

  • 中缀表示法:操作符号处于两个操作数的中间例如3+4,中缀表达式是符合人们思维的算术表达式方法,中缀表达式通常包含圆括号和方括号。中缀表达式不容易被计算机所理解,因此不太方便使用其进行表达式求值。

    中缀表示的例子 1 + 3 * (4 + 5)

  • 后缀表达式:不包含括号,运算符号放在两个运算对象的后面,所有的计算按运算符号出现的顺序,严格的从左向右进行运算(不再需要考虑运算符号的优先规则)。

    后缀表达式的例子21+3* 对应中缀表达式为(2+1)*3

后缀表达式求值

使用后缀表达式进行求值的时候,不需要考虑括号和运算符号的优先规则,只需要从左到右进行计算求值即可。

后缀表达式的求值过程为:

  1. 读入操作数,压入栈中直到读取到操作符
  2. 如果读取到为操作符,则将栈顶的前两元素出栈,使用该操作符进行运算,得到计算结果
  3. 将计算结果压入栈中
  4. 重复1、2、3直到表达式末尾

最后栈中只有一个元素,变为最后的计算结果。将其出栈即可。

例如:
中缀表达式(2+1)*3
对应的后缀表达式为21+3*

  • 初始化栈S
  • 读取2和1压入S,此时S为1,2
  • 读取到操作符+,出栈栈顶两元素得到1,2,此时栈为空
  • 使用操作符计算两操作数,得到3(1 + 2 = 3),将3压入栈S,此时栈S为3
  • 读入3,压入栈S,此时栈为3,3
  • 读取到操作符*,出栈栈顶两元素得到3,3 此时栈S为空
  • 使用操作符*,对两元素进行运算得到9,将9压入栈S
  • 读取到表达式尾部

出栈栈顶元素得到9即为计算结果

计算机通常使用后缀表达式进行表达式求值,但是人们通常输入计算的表达式是中缀表达式,因此在进行表达式求值的时候,应该先将中缀表达式转为后缀表达式,然后使用后缀表达式求出表达式值。后缀表达式求值的过程很简单,已经上面分析过了。现在关键的一步就是中缀表达式转为后缀表达式。

中缀表达式转后缀表达式

中缀表达式转后缀表达式是表达式求值关键的一步,其过程如下:
输入中缀表达式IEXP,
输出后缀表达式SEXP
依次读入中缀表达式IEXP,初始化一个栈S用来存放操作符OP。

  1. 如果读取的是操作数,直接输出到SEXP。如果为操作符OP,进入step2,如果为空,证明读取到IEXP尾部,则进入step5
  2. 判断OP,若为(,无任何输出,直接压栈(到S,进入step1;若为),则出栈S的元素输出到SEXP中直到遇见元素(,且(不输出到SEXP中,然后进入step1;若OP不为(),则执行step3
  3. 判断栈S的栈顶元素是否为(,若为,则直接将OP压栈到S中;若不为(,则将栈S的元素出栈输出到SEXP中,直到栈顶元素的优先级小于OP或者栈空,最后进入step4
  4. 将OP压入栈S中,进入step1
  5. 将栈所有元素输出到SEXP中

例如
IEXP为(2+1)*3
初始化一个空栈S.

  • 读取到操作符(,直接压入栈S,此时栈S为(、

  • 读取到操作数2,则直接输出到SEXP,此时S仍为,SEXP为 2

  • 读取到操作符号+,由于栈S栈顶元素为(,因此直接将+,压入栈S中,此时SEXP为2,栈S为(、+

  • 读取到操作数1,直接输出,此时SEXP为21, 栈S为(、+

  • 读取到操作符),则出栈S的元素直到碰见(,不输出(),则SEXP为21+,栈S为空

  • 读取到操作符号*'压栈到S,此时SEXP仍为21+,栈S为*

  • 读取到操作数3,直接输出到SEXP中,SEXP为21+3,栈S为*

  • 读取到文件尾,则出栈S知道栈空,SEXP为21+3*

    最后得到后缀表达式21+3*

    可见,中缀转后缀的关键点在于读取到的操作符为括号的case,栈中的(保留直到遇见操作符),否则是不会出栈的。

代码示例


//int栈
#include <stdio.h>
#include <malloc.h>
#define INCREMENT 20

struct Stack_{
    int* a;
    int capacity;
    int size;
    int top;
};

int pop_(struct Stack_* stack) {
    if(stack->size <= 0 || stack->top < 0)
        return NULL;
    stack->size--;
    return stack->a[stack->top--];
}

void push_(struct Stack_* stack, int c) {
    //扩容
    if(stack->size <= stack->capacity) {
        stack->capacity += INCREMENT;
        int* p = (int*)malloc(sizeof(int) * ( stack->capacity));
        int i;
        int* q;
        q = p;
        for(i = 0; i < stack->size; i++) {
            *(q++) = *(stack->a++);
        }
        stack->a = p;
    }

    //压栈
    stack->size++;
    stack->top++;
    stack->a[stack->top] = c;
}

struct Stack_* initStack_(int capacity) {
    struct Stack_* stack = (struct Stack_*)malloc(sizeof(struct Stack_));
    int* a = (int*)malloc(sizeof(int) * capacity);
    stack->size = 0;
    stack->top = -1;
    stack->a = a;
    return stack;
};

//测试是否字符数组是否存在test字符
int in(char* a, int n, char test) {
    int i = 0;
    for(i; i < n; i++) {
        if(a[i] == test)
            return 1;
    }
    return 0;
}

//优先级比较
int compare(char a, char b) {

    if(a == b)
        return 0;

    if(a == '+') {
        if(b == '*' || b == '(' || b == ')')
            return -1;
    }

    if(a == '*') {
        if(b == '+')
            return +1;
        if(b == '(' || b == ')')
            return -1;
    }
}

//中缀表达式转为后缀表达式
char* infix2Suffix(char* infix, int n) {
    struct Stack* stack = initStack(n);
    char add = '+';
    char mult = '*';
    char left = '(';
    char right = ')';
    char op[4] = {'+', '*', '(', ')'};
    int i = 0;
    char *result = (char*)malloc(sizeof(char) * n);
    char top;
    int j = 0;

    for(i; i < n; i++) {
        char c = infix[i];
        //如果读取的字符不为操纵符,为操作数
        //直接放入输出字符数组中
        if(!in(op, 4, c))
            result[j++] = c;
        else {//开始将操作符压栈
            if(stack->size == 0)
                push(stack, c);
            else {
                //
                if(c != '(' && c != ')') {
                    while(1) {
                        top =  pop(stack);
                        if(top == NULL)
                            break;
                        if(top == '(' || compare(c, top) > 0) {
                            push(stack, top);
                            break;
                        } else if (compare(c, top) <= 0)
                            result[j++] = top;
                    }
                    push(stack, c);
                }

                if(c == '(')
                    push(stack, c);

                if(c == ')') {
                    while(1) {
                        top =  pop(stack);
                        if(top != NULL && top != '(')
                            result[j++] = top;
                        else
                            break;
                    }
                }


            }
        }
    }
    //输出栈中剩余的内容
    while(1) {
        top = pop(stack);
        if(top == NULL)
            break;
        result[j++] = top;
    }
    result[j++] = '#';
    return result;
}

//中缀表达式求值
int evaluate(char* infix, int n) {
    char *suffix = infix2Suffix(infix, n);
    struct Stack_* stack = initStack_(n);
    char op[4] = {'+', '*', '(', ')'};
    int i = 0;
    char opnum1, opnum2;
    char c;

    while((c = suffix[i++]) != '#') {
        if(!in(op, 4, c))
            push_(stack, (int)c - (int)'0');
        else if(in(op, 4, c)){
            int opnum1 = pop_(stack);
            int opnum2 = pop_(stack);
            int tmp;
            if(c == '+')
                tmp = opnum1 + opnum2;
            if(c == '*')
                tmp = opnum1 * opnum2;
            push_(stack, tmp);
        }
    }

    return pop_(stack);
}

int main() {

    char infixExp[13] = {'6', '+', '5', '+', '7',
                        '*', '8', '*', '(', '1',
                        '+', '2', ')'};
    int result = evaluate(infixExp, 13);
    char *suffixExp = infix2Suffix(infixExp, 13);
    printf("\n");
    while(*suffixExp!= '#')
        printf("%c", *suffixExp++);
    printf("\n%d", result);
    return;
}
2020-02-16 14:23:32 qq_40527086 阅读数 21
  • input子系统基础之按键-linux驱动开发第8部分

    本课程是linux驱动开发的第8个课程,主要内容是linux的input子系统。学习本课程的目标是对input子系统的框架结构有深入理解,应用层和驱动层的调用关系和方法完全了解,能够自己移植按键等常见输入类设备的驱动。

    5164 人正在学习 去看看 朱有鹏

栈(stack) 是一种先入后出的线性结构
应用:子程序的调用/递归调用/表达式求值(中缀表达式转后缀表达式)/二叉树遍历/图的DFS

使用数组来模拟栈

初始化:top = -1
入栈:top++,stack[top] = data
出栈: int value = stack[top], top–,return value

package com.like.java.data_structure.stack;

// 表示栈结构
public class ArrayStack {
	// 栈的大小
	private int maxSize;
	private int[] stack;
	private int top = -1;
	public ArrayStack(int maxSize)
	{
		this.maxSize = maxSize;
		stack = new int[this.maxSize];
	}
	
	public boolean isFull()
	{
		return top == (maxSize-1);
	}
	
	public boolean isEmpty()
	{
		return top == -1;
	}
	
	public void push(int val)
	{
		if(isFull())
		{
			System.err.println("Full");
			return;
		}
		stack[++top] = val;
	}
	
	public int pop()
	{
		if(isEmpty())
		{
			throw new RuntimeException("Empty Stack,No data");
		}
		return stack[top--];
	}
	
	public void show()
	{
		if(isEmpty())
		{
			throw new RuntimeException("Empty Stack,No data");
		}
		for(int i=top;i>=0;i--)
		{
			System.out.println("stack["+i+"]="+stack[i]);
		}
	}
}

使用链表来模拟栈

package com.like.java.data_structure.stack;
import com.like.java.data_structure.linkedList.Boy;

public class LinkedStack {
	private Boy bottom = new Boy(-1);
	private Boy top = bottom;
	
	public boolean isEmpty()
	{
		return bottom == top;
	}
	
	public void push(Boy boy)
	{
		boy.next = top;
		top = boy;
	}
	
	public Boy pop()
	{
		if(isEmpty())
		{
			System.err.println("Empty Stack");
			return null;
		}
		
		Boy curBoy = top;
		top = top.next;
		return curBoy;
	}
	
	public void show()
	{
		Boy temp = top;
		while(temp != bottom)
		{
			System.out.println(temp);
			temp = temp.next;
		}
	}
}

使用栈实现综合计算器

对于一个中缀表达式形如722-5+1+5+3-4,使用栈来计算综合的结果
思想:1. 通过一个index值来遍历表达式
2. 如果是一个数字,直接加入到数栈中
3. 如果是运算符,分为两种情况
- 3.1 若符号栈为空,直接入栈
- 3.2 若符号栈不为空,比较当前操作符和栈中操作符进行比较
当前运算符小或等于栈中,就从数栈中pop出两个数,从符号栈中pop出一个,运算出结果入数栈,然后将当前操作符如符号栈(Note 后面弹出的数 操作符 前面弹出的数)
当前运算符优先级大于栈中的操作符,直接入符号栈
4. 当表达式扫描完毕后,就顺序地从数栈和符号栈中pop出相应的数和符号栈就行运算,最后数栈中只有一个数值即运算结果

package com.like.java.data_structure.stack;

// 用于综合计算器
public class ArrayStack2 {
	// 栈的大小
	private int maxSize;
	private int[] stack;
	private int top = -1;
	public ArrayStack2(int maxSize)
	{
		this.maxSize = maxSize;
		stack = new int[this.maxSize];
	}
	
	public boolean isFull()
	{
		return top == (maxSize-1);
	}
	
	public boolean isEmpty()
	{
		return top == -1;
	}
	
	public void push(int val)
	{
		if(isFull())
		{
			System.err.println("Full");
			return;
		}
		stack[++top] = val;
	}
	
	public int pop()
	{
		if(isEmpty())
		{
			throw new RuntimeException("Empty Stack,No data");
		}
		return stack[top--];
	}
	
	public void show()
	{
		if(isEmpty())
		{
			throw new RuntimeException("Empty Stack,No data");
		}
		for(int i=top;i>=0;i--)
		{
			System.out.println("stack["+i+"]="+stack[i]);
		}
	}
	
	// 增加优先级判断功能
	// 优先级使用数字表示,数字越大,优先级越大
	public int priority(int oper)
	{
		if(oper == '*' || oper == '/')
		{
			return 1;
		}
		else if(oper == '+' || oper == '-')
		{
			return 0;
		}else {
			return -1;
		}
	}

	// 判断是不是运算符
	public boolean isOper(int oper)
	{
		return oper == '+' || oper == '-' || oper == '*' || oper == '/';
	}
	
	// 计算方法
	public int calc(int num1, int num2, int oper)
	{
		int res = 0;
		switch(oper)
		{
		case '+':
			res = num1 + num2;
			break;
		case '-':
			res = num2 - num1;
			break;
		case '*':
			res = num1*num2;
			break;
		case '/':
			res = num2/num1;
			break;
	    
		}
		return res;
	}

	// peek
	public int peek()
	{
		return stack[top];
	}
}

package com.like.java.data_structure.stack;

public class Calculator {
	public static void main(String[] args) {
		String expression = "3+2*6-2*9";
		
		ArrayStack2 numStack2 = new ArrayStack2(10);
		ArrayStack2 operStack2 = new ArrayStack2(10);
		
		int index = 0; // 扫描
		int num1 = 0,num2 = 0;
		int res = 0;
		int oper = 0;
		char ch = ' ';
		
		// 扫描入栈
		while(index < expression.length())
		{
			ch = expression.charAt(index++);
			if(operStack2.isOper(ch))
			{
				if(!operStack2.isEmpty())
				{
					if(operStack2.priority(ch) <= operStack2.priority(operStack2.peek()))
					{
						num1 = numStack2.pop();
						num2 = numStack2.pop();
						oper = operStack2.pop();
						res = operStack2.calc(num1, num2, oper);
						numStack2.push(res);
						// 当前操作符入符号栈
						operStack2.push(ch);
					}else {
						operStack2.push(ch);
					}
				}
				else {
					operStack2.push(ch);
				}
			}else {
				numStack2.push(ch-48);
			}
		}
		
		// 扫描完毕运算到符号栈为空
		while(!operStack2.isEmpty())
		{
			num1 = numStack2.pop();
			num2 = numStack2.pop();
			oper = operStack2.pop();
			res = operStack2.calc(num1, num2, oper);
			numStack2.push(res);
		}
		
		System.out.printf("%s=%d",expression,numStack2.pop());
	}
}

Java.util.Stack示例

package com.like.java.data_structure.stack;

import java.util.Stack;

public class StackTester {
	public static void main(String[] args) {
		Stack<String> stack = new Stack<String>();
		// 入栈
		stack.setSize(3);
		stack.add("Jack");
		stack.add("Tom");
		stack.add("Alice");
		
		String isPush = stack.push("Like");
		boolean isAdd = stack.add("Smith");
		
		System.out.println(isPush);
		System.out.println(isAdd);
		// 出栈
	    System.out.println(stack.pop());
	
		// 查看栈顶元素
		System.out.println(stack.peek());
		
		//查看栈大小
		System.out.println(stack.size());
		
	}
}

阅读数 38

内存中堆和栈

阅读数 217

没有更多推荐了,返回首页