数据结构 - 栈和队列(C语言实现)

一.

  1. 栈的定义

    (Stack)是一种只能在一端进行插入或删除操作的线性表
          栈的示意图
                  图一 栈的示意图

  2. 顺序栈的基本操作
    初始化

    void InitStack(Stack *S){
    	//初始化顺序栈即使栈顶指针为-1 
    	S->Top = -1;	
    } 
    

    栈判空

    int StackEmpty(Stack *S) {
    	//栈判空函数
    	if(S->Top == -1)	//栈空 
    		return 1;
    	else				//非空 
    		return 0; 
    }
    

    进栈

    int Push(Stack *S, int e){
    	//进栈函数
    	if(S->Top == StackMaxSize-1)//栈满
    		return ERROR; 
    	else{
    		S->Data[++(S->Top)] = e;	//栈顶指针加一,存储元素 
    		return OK; 
    	}
    } 
    

    出栈

    int Pop(Stack *S, int *e){
    	//出栈并将元素传给e 
    	if(S->Top == -1)	//栈空
    		return ERROR;
    	else{
    		*e = S->Data[S->Top--];//传递元素,栈顶指针减一 
    		return OK;		
    	} 
    }
    

    操作结果
        操作结果

  3. 共享栈
      利用栈一段操作的特性,我们可以实现两个栈共享一个一维数组空间,将两个栈底分别设置在数组的两端,两个栈顶分别向中间延伸,当两个栈顶指针相遇时即为栈满。
    共享栈示意图

  4. 链栈
     采用链式存储结构的栈称为链栈,链栈相比顺序栈的优点是多个栈可以共享存储空间,并且几乎不存在栈满上溢的状况。

     链栈示意图

二. 队列

  1. 队列的定义
     队列也是一种操作受限的线性表,和栈不同的是,队列只允许在一段插入在另一端取出。
    队列示意图
     队头:允许删除的一端,又称为队首。
     队尾:允许插入的一端。

  2. 队列的顺序存储
     队列的顺序存储是指分配一块连续的存储单元存放队列中的元素,并附两个指针front和rear分别指示队头和队尾元素的位置。但是很大的缺点是当经过一次队满出队操作后就无法再对队列进行操作。
          顺序队列示意图
                 顺序队列示意图

  3. 循环队列
     循环队列就是将前面的顺序队列定义为环状,将存储空间在逻辑上表示成一个环,这样只有元素占满存储单元的时候才会判队列满。但是为了区别队列满和队列空则需要牺牲一个存储单元。
       在这里插入图片描述
    定义

    #define QueueMaxSize	10
    #define ERROR		0
    #define OK			1
    
    typedef struct{
    	int Data[QueueMaxSize];//存放队列元素 
    	int frond;	//队头指针 
    	int rear;	//队尾指针 
    }Queue; 
    

    初始化

    void InitQueue(Queue *Q){
    	//初始化循环队列
    	Q->frond = Q->rear = 0; 
    } 
    

    判空

    int isEmpty(Queue Q){
    	//循环队列判空
    	if(Q.frond == Q.rear)//队列空 
    		return OK;
    	else
    		return ERROR; 	//队列非空 
    }
    

    入队

    int EnQueue(Queue *Q, int e){
    	//入队操作
    	if((Q->rear+1)%QueueMaxSize == Q->frond)//队满 
    		return ERROR;
    	else{
    		Q->Data[Q->rear] = e;
    		Q->rear = (Q->rear + 1)% QueueMaxSize;//队尾指针加一取模 
    		return OK;
    	} 
    } 
    

    出队

    int DeQueue(Queue *Q, int *e){
    	//出队操作
    	if(isEmpty(*Q) == OK)//队空报错 
    		return ERROR;
    	else{
    		*e = Q->Data[Q->frond];
    		Q->frond = (Q->frond + 1)%QueueMaxSize;//队头指针加一取模 
    		return OK;
    	}
    } 
    

    测试
       结果

  4. 链队列
     队列的链式存储称为链队列,它实际上是一个同时拥有头指针和尾指针的单链表。头指针指向队头节点,尾指针指向队尾结点。
    链队列示意图
                  不带头结点的链队列示意图

    定义

    typedef struct LNode{//节点 
    	int Data;		//数据 
    	struct LNode *Next;//指针 
    }Node; 
    
    typedef struct{
    	Node *front;	//队头指针 
    	Node *rear;		//队尾指针 
    }LinkQueue;
    

     和之前不同的是链队这个结构体里面包含队头队尾两个指针,而两个指针指向的数据节点,所以需要定义两个结构体。

    初始化

    void  LinkQueueInit(LinkQueue *Q){
    	//初始化队列
    	Q->front = Q->rear = (Node *)malloc(sizeof(Node));
    	if(Q->front == NULL)
    		exit(-1);	//申请内存失败 
    	Q->front->Next = NULL;	//初始化为空 
    }
    

    判空

    int IsEmpty(LinkQueue Q){
    	//判队列空
    	if(Q.front == Q.rear)
    		return true;
    	else
    		return false; 
    } 
    

    入队

    int EnQueue(LinkQueue *Q,int e){
    	//入队操作
    	Node *q=NULL;
    	q = (Node *)malloc(sizeof(Node));
    	if(q == NULL)	exit(-1);//内存分配失败
    	q->Data = e;			//修改新节点 
    	q->Next = NULL;
    	Q->rear->Next = q;	
    	Q->rear = q;
    	return OK;
    }
    

    出队

    int DeQueue(LinkQueue *Q,int *e){
    	//出队操作
    	Node *q=NULL; 
    	
    	if(IsEmpty(*Q) == true) 
    		return ERROR;		//空队无法进行出队操作
    	q = Q->front->Next;
    	*e = q->Data;
    	Q->front->Next = q->Next;//队头后移 
    	if(Q->rear == q)		//为了防止队列空释放掉q后队尾指针变为野指针需要指向头结点 
    		Q->rear = Q->front;
    	free(q);	//释放出队节点 
    	return OK; 
    	 
    }
    

    测试
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40344307/article/details/89286080