队列 和 栈 的区别 剖析

1.队列先进先出,栈先进后出。
       2. 对插入和删除操作的"限定"。 栈是限定只能在表的一端进行插入和删除操作的线性表。      队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。     从"数据结构"的角度看,它们都是线性结构,即数据元素之间的关系相同。但它们是完全不同的数据类型。除了它们各自的基本操作集不同外,主要区别是对插入和删除操作的"限定"。     栈和队列是在程序设计中被广泛使用的两种线性数据结构,它们的特点在于基本操作的特殊性,栈必须按"后进先出"的规则进行操作,而队列必须按"先进先出" 的规则进行操作。和线性表相比,它们的插入和删除操作受更多的约束和限定,故又称为限定性的线性表结构。

3.遍历数据速度不同。栈只能从头部取数据 也就最先放入的需要遍历整个栈最后才能取出来,而且在遍历数据的时候还得为数据开辟临时空间,保持数据在遍历前的一致性队列怎不同,他基于地址指针进行遍历,而且可以从头或尾部开始遍历,但不能同时遍历,无需开辟临时空间,因为在遍历的过程中不影像数据结构,速度要快的多

栈(Stack)是限定只能在表的一端进行插入和删除操作的线性表。
队列(Queue)是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
从"数据结构"的角度看,它们都是线性结构,即数据元素之间的关系相同。但它们是完全不同的数据类型。除了它们各自的基本操作集不同外,主要区别是对插入和删除操作的"限定"。

栈和队列是在程序设计中被广泛使用的两种线性数据结构,它们的特点在于基本操作的特殊性,栈必须按"后进先出"的规则进行操作,而队列必须按"先进先出"的规则进行操作。和线性表相比,它们的插入和删除操作受更多的约束和限定,故又称为限定性的线性表结构。可将线性表和栈及队列的插入和删除操作对比如下:

 
线性表
 Insert(L,i,x)
(1≤i≤n+1)
 Delete(L,i)
(1≤i≤n)
 如线性表允许在表内任一位置进行插入和删除
 
栈
 Insert(L,n+1,x)
 Delete(L,n)
 而栈只允许在表尾一端进行插入和删除
 
队列
 Insert(L,n+1,x)
 Delete(L,1)
 队列只允许在表尾一端进行插入,在表头一端进行删除


栈的抽象数据类型
    栈的抽象数据类型中的数据部分为具有ElemType元素类型的一个栈,它可以采用任一种存储结构实现;操作部分包括元素进栈、出栈、读取栈顶元素、检查栈是否为空等。下面给出栈的抽象数据类型的具体定义。
        ADT STACK is
            Data:
                采用顺序或链接方式存储的栈,假定其存储类型用StackType
                标识符表示。
            Operation:
                void InitStack(StackType& S);
                        // 初始化栈S,即把它置为空
                void ClearStack(StackType& S);
                        // 清除栈S中的所有元素,使之成为一个空栈
                int StackEmpty(StackType& S);
                        // 判断S是否为空,若是则返回1,否则返回0
                ElemType Peek(StackType& S)
                        // 返回S的栈顶元素,但不移动栈顶指针
                void Push(StackType& S, const ElemType& item)
                        // 元素item进栈,即插入到栈顶
                ElemType Pop(StackType& S)
                        // 删除栈顶元素并返回之
               int StackFull(Stack& S)
                       // 若栈已满则返回1,否则返回0,此函数为顺
                       // 序存储的栈所特有
        end STACK
    对于判断栈是否为空和返回栈顶元素的两种操作,由于它们不改变栈的状态,所以可在参数类型说明前使用常量定义符const。
    假定栈a的元素类型为int,下面给出调用上述栈操作的一些例子。
(1) InitStack(a);  // 把栈a置空
    (2) Push(a,35);  // 元素35进栈
 (3) int x=48; Push(a,x);  // 48进栈
 (4) Push(a,x/2);  // x除以2的值24进栈
 (5) x=Pop(a);  // 栈顶元素24退栈并赋给x
 (6) x=Peek(a);  // 读取栈顶元素48并赋给x
 (7) Pop(a);  // 栈顶元素48退栈
    (8) StackEmpty(a);  // 因栈非空,应返回0  
 (9) cout<<Pop(a)<<endl;  // 栈顶元素35退栈并输出
    (10) x=StackEmpty(a);  // 因栈为空,应返回1,然后赋给x
   
    4. 栈运算的实现
    栈运算(操作)的具体实现取决于栈的存储结构,存储结构不同,其算法描述也不同。下面分别给出栈的运算在顺序存储结构和链接存储结构上实现的具体算法。
    (a) 栈的操作在顺序存储结构上的实现
    假定采用顺序存储结构定义的栈用标识符S 表示,其类型为已经给出过的Stack记录类型。
(1) 初始化栈
        void InitStack(Stack& S)
                // 初始化栈S,即把它置为空
        {
         S.top=-1;  
        }
    (2) 把一个栈清除为空
    在顺序存储方式下,同初始化栈的算法相同。
        void ClearStack(Stack& S)
                // 清除栈S中的所有元素,使之成为一个空栈
        {
         S.top=-1;
        }
    (3) 检查一个栈是否为空
        int StackEmpty(Stack& S)
                // 判断S是否为空,若是则返回1,否则返回0
        {
         return S.top==-1;
        }
    (5) 读取栈顶元素
        ElemType Peek(StackType& S)
                // 返回S的栈顶元素,但不移动栈顶指针
        {
       // 若栈为空则终止程序运行
            if(S.top==-1) {
          cerr<<"Stack is empty!"<<endl;
          exit(1);
         }
          // 返回栈顶元素的值
         return S.stack[S.top];
        }
    (5) 向栈中插入元素
        void Push(Stack& S, const ElemType& item)
                // 元素item进栈,即插入到栈顶
        {
          // 若栈已满则终止程序运行
         if(S.top==StackMaxSize-1) {
          cerr<<"Stack overflow!"<<endl;
          exit(1);
         }
          // 将栈顶指针后移一个位置
         S.top++;
          // 将item的值赋给新的栈顶位置
         S.stack[S.top]=item;
        }
    (6) 从栈中删除元素 
        ElemType Pop(StackType& S)
                // 删除栈顶元素并返回之
        {
       // 若栈为空则终止程序运行
         if(S.top==-1) {
          cerr<<"Stack is empty!"<<endl;
          exit(1);
         }
          // 暂存栈顶元素以便返回
            ElemType temp=S.stack[S.top];
          // 栈顶指针前移一个位置
         S.top--;
          // 返回原栈顶元素的值
         return temp;
    }
    从出栈算法可以看出,原栈顶元素的值没有被改变,所以可以不使用临时变量保存它,返回语句中返回S.stack[S.top+1]的值即可。
    (7) 检查栈是否已满
        int StackFull(Stack& S)
              // 若栈已满则返回1,否则返回0,此函数为顺序栈所特有
        {
         return S.top==StackMaxSize-1; 
        }
    (b) 栈的操作在链接存储结构上的实现
假定链栈中的结点仍采用在第二章中已经定义的LNode结点类型,并假定栈顶指针用HS表示,下面给出对由HS所指向的链栈进行每一种栈操作的算法。
    (1) 初始化链栈
        void InitStack(LNode*& HS)
        {
            HS=NULL;  // 将链栈置空。
        }
    (2) 清除链栈为空
        void ClearStack(LNode*& HS)
        {
         LNode *cp, *np;  
              // 用cp作为指向待删除的结点,np指向cp的后继结点。
         cp=HS;  // 给cp指针赋初值,使之指向栈顶结点。
         while(cp!=NULL) 
         { // 从栈顶到栈底依次删除每个结点
          np=cp->next; 
          delete cp;  
          cp=np;  
         }
         HS=NULL;  // 置链栈为空
        }
    (3) 检查链栈是否为空
        int StackEmpty(LNode* HS)
                 // HS为值参或引用形参均可
        {
         return HS==NULL;
        }
    (4) 读取栈顶元素
        ElemType Peek(LNode* HS)  // HS为值参或引用形参均可
        {
         if(HS==NULL)  {
          cerr<<"Linked stack is empty!"<<endl;
          exit(1);
         }
            return HS->data;
        }
    (5) 向链栈中插入一个元素
        void Push(LNode*& HS, const ElemType& item)
        {
          // 为插入元素获取动态结点
         LNode* newptr= new LNode;
         if(newptr==NULL)  {
          cerr<<"Memory allocation failare!"<<endl;
          exit(1);
         }
          // 给新分配的结点赋值
         newptr->data=item;
          // 向栈顶插入新结点
         newptr->next=HS;
         HS=newptr;
        }
    (6) 从链栈中删除一个元素
        ElemType Pop(LNode*& HS)
        {
         if(HS==NULL) {
          cerr<<"Linked stack is empty!"<<endl;
          exit(1);
         }
         LNode* p=HS;  // 暂存栈顶结点
         HS=HS->next;  // 使栈顶指针指向其后继结点
         ElemType temp=p->data;  // 暂存原栈顶元素
            delete p;  // 回收原栈顶结点
         return temp;  // 返回原栈顶元素
        }



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值