您的位置:首页 > 理论基础 > 数据结构算法

数据结构第三章

2014-10-25 18:39 288 查看
 3.1     栈
3.1.1    栈的逻辑结构
1.栈(stack)是限定仅在表尾进行插入和删除操作的线性表,允许插入和删除的而一端称为栈顶,另一端称为栈底。不含任何元素的栈称为空栈。
 
2.栈的特性:后进先出(在任何时候出栈的元素都只能是栈顶元素,即最后入栈者最先出栈)。
 
3.
栈的抽象数据类型定义

ADT Stack
Data
 
栈中元素具有相同类型及后进先出的特性,相邻元素具有前驱和后继关系
Operation
   InitStack
     
前置条件:栈不存在
     
输入:无
     
功能:栈的初始化
     
输出:无
     
后置条件:构造一个空栈
DestroyStack
      前置条件:栈已存在
     
输入:无
     
功能:销毁栈
     
输出:无
     
后置条件:释放栈所用的存储空间
Push
      前置条件:栈已存在
     
输入:元素值x
     
功能:入栈操作,在栈顶插入一个元素x
     
输出:如果插入不成功,则抛出异常
     
后置条件:如果插入成功,则栈顶增加了一个元素
Pop
      前置条件:栈已存在
     
输入:无
     
功能:出栈操作,删除栈顶元素
     
输出:如果删除成功,返回被删元素值,否则,抛出异常
     
后置条件:如果删除成功,则栈顶少了一个元素
GetTop
     
前置条件:栈已存在
  
     
输入:无
     
功能:取栈顶元素,读取当前的栈顶元素
     
输出:若栈不空,返回当前的栈顶元素值
     
后置条件:栈不变
Empty
 
  
     
前置条件:栈已存在
     
输入:无
     
功能:判空操作,判断栈是否为空
     
输出:如果栈为空,返回1,否则,返回0
     
后置条件:栈不变
endADT
3.1.2    栈的顺序存储结构及实现
1.  栈的顺序存储结构——顺序栈
     通常把数组中下标为0的一端作为栈底。
           指针top指示栈顶元素在数组中的位置。
     StackSize:存储栈元素的数组长度。                   
栈空:top= -1     
栈满:top=StackSize -1
2.  顺序栈的实现
  将栈的抽象数据类型定义在顺序栈存储结构下用c++中的类实现。由于栈元素的数据类型不能确定,因此采用c++的模板机制。
 
const  int  StackSize=10;     // 10只是示例性的数据,可以根据实际问题具体定义
template  <class  datatype>  //定义模板类SeqStack
class  SeqStack
{
 public:
    SeqStack(){top= -1;}           //构造函数,初始化一个空栈
   ~ SeqStack(){ }               //析构函数为空
 Void push(DataType x); 
//入栈操作,将元素x入栈
DataType pop();    
//出栈操作,将栈顶元素弹出
DataType GetTop(){if(top!=-1) return data[top];} //取栈顶元素
Int Empty(){top==-1?return 1:return 0;}
Private:
Datatype data[StckMaxsize];
Int top;
                
} ;
(1) 
栈的初始化
初始化一个空栈只需将栈顶指针top置为-1。
(2)入栈操作
在栈中插入元素x只需将栈顶指针top加1,然后在top指向的位置填入元素x,算法如下:
template<class DataType>
void SeqStack<DataType>::Push(DataTypex)
{
 
If(top==StackSize-1)throw”上溢”;
 data[++top=x;]
}
(3)出栈操作
删除栈顶元素只需取出栈顶元素,然后将栈顶指针top减1,算法如下:
Template<class DataType>
DataType SeqStack<DataType>::pop()
{
 If(top==-1)throw”下溢”;
 X=data[top--];
 returnx;
}
(4)取栈顶元素
取栈顶元素只是将top指向的栈顶元素取出,并不修改栈顶指针。
(5)判空操作
顺序栈的判空操作只需判断top==-1是否成立,如果成立,则栈为空,返回1;如果不成,则栈非空,返回0。
3. 两栈共享空间
两共享占空间入栈算法push
Template <class DataType>
Void BothStack<DataType>::push(inti,DataType x)
{
 
If(top1==top2-1)throw”上溢”;
If(i==1)data[++top1]=x;
If(i==2)data[--top]=x;
}
两栈共享空间出栈算法Pop
Template <class DataType>
DataType BothStack<DataType>::Pop(inti)
{
 
If(i==1)
  
If(top1==-1)throw“下溢”;
 
Returndata[top--];
}
If(i==2)
If(top2==StackSize)throw”下溢”;
Return data[top2++];
 
}
}
3.13       栈的链接存储结构及实现
1.   栈的链接存储结构——链栈
栈的链接存储结构称为链栈。
2.   链栈的实现
⑴构造函数
构造函数的作用是初始化一个空链栈,由于链栈不带头结点,因此只需将栈顶指针top置为空。
⑵入栈操作
链栈入栈算法Push
Template<classDataType>
VoidLinkStack<DataType>::Push(DataType x)
{
S=newNode;s->data=x;
s->next=top;top=s;
}
⑶出栈操作
链栈出栈算法Pop
Template<classDataType>
DataTypeLinkStack<DataType>::Pop()
{
If(top==NULL)throw“下溢”;
X=top->data;p=top;
Top=top->next;
Deletep;
Returnx;
}
⑷取栈顶元素
取栈顶元素只需返回栈顶指针top所指结点的数据域。
⑸判空操作
链栈的判空操作只需判断top==NULL是否成立。如果成立,则栈为空,返回1;如果不成立,则栈非空,返回0。
⑹析构函数
链栈的析构函数需要将链栈中所有结点的存储空间释放,算法与单链表类的析构函数类似,算法略。
3.14       顺序栈和链栈的比较
实现顺序栈和链栈的所有基本操作的算法都只需要常数时间,因此唯一可以比较的是空间性能。初始时顺序栈必须确定一个固定的长度,所以有存储元素个数的限制和空间浪费的问题。链栈没有栈满的问题,只有当内存没有可用空间时才会出现栈满,但是每个元素都需要一个指针域,从而产生了结构性开销。所以当栈的使用过程中元素个数变化较大时,用链栈是适宜的;反之,应该采用顺序栈。
3.2 队列

3.2.1队列的逻辑结构

1.定义:队列只允许在一端进行插入操作,在另一端进行删除操作的线性表。

允许插入的一端称为队尾,允许删除的一端称为队头。(先进先出)

2.队列的抽象数据类型定义

ADT  Queue

        InitQueue

               前置条件:队列不存在

               输入:无

               功能:初始化队列

               输出:无

               后置条件:创建一个空队列

     DestroyQueue

               前置条件:队列已存在

               输入:无

               功能:销毁队列

               输出:无

               后置条件:释放队列所占用的存储空间

    EnQueue

              前置条件:队列已存在

            输入:元素值x

            功能:入队操作,在队尾插入一个元素

            输出:如果插入不成功,抛出异常

            后置条件:如果插入成功,队尾增加了一个元素

    DeQueue

          前置条件:队列已存在

          输入:无

          功能:出队操作,删除队头元素

          输出:如果删除成功,返回被删元素值,否则,抛出删除异常

          后置条件:如果删除成功,队头减少了一个元素

  GetQueue

          前置条件:队头已存在

          输入:无

          功能:读取队头元素

         输出:若队列不空,返回队头元素

         后置条件:队列不变

 Empty

         前置条件:队列不存在

         输入:无

         功能:判空操作,判断队列是否为空

         输出:如果队列为空,返回1,否则返回0

         后置条件:队列不变

endADT

3.2.2队列的顺序存储结构及实现

循环队列:队列的头尾相接的顺序存储结构称为循环队列。

约定:队头指针front指向队头元素的前一个位置,队尾指针rear指向队尾元素。

假溢出:当元素被插入到数组中下标最大的位置上之后,队列的空间就用尽了,尽管此时数组的低端还有空闲空间,这种现象叫做“假溢出”。

队空和队满的判定:队空front=rear

                            队满(rear+1)%QueueSize==front

循环队列的实现

const int QueueSize=100;                           //定义存储队列元素的数组的最大长度

template<class DataType>                           //定义模板类CirQueue

class CirQueue

{

public:

      CirQueue(){front=rear=QueueSize;}              //构造函数,初始化空队列

      ~CirQueue(){}                                  //析构函数为空

      voidEnQueue(DataType x);                     //入队操作,将元素x入队

      DataTypeDeQueue();                            //出队操作,将队头元素出队

      DataTypeGetQueue();                           //读取队头元素(并不删除)

      intEmpty(){front==rear?return 1:return 0;}   //判断队列是否为空

private:

      DataTypedata[QueueSize];                     //存放队列元素的数组

      intfront,rear;                              //队头和队尾指针

};

(1)   
构造函数

构造函数的作用是初始化一个空的循环队列,只需将队头指针和队尾指针同时指向数组的某一个位置,一般是数组的高端,即rear=front=QueueSize-1。

(2)   
入队操作

template <class DataType>

voidCirQueue<DataType>::EnQueue(DataType x)

{

      if((rear+1)%QueueSize==front) throw"上溢";

      rear=(rear+1)%QueueSize;                    //队尾指针在循环意义下加1

      data[rear]=x;                               //在队尾处插入元素

}

(3)   
出队操作

template <class DataType>

DataTypeCirQueue<DataType>::DeQueue()

{

      if(rear==front) throw"下溢";

      front=(front+1)%QueueSize;                  //队头指针在循环意义下加1

      returndata[front];                         //读取并返回出队前的队头元素

}

(4)   
读取队头元素

template <class DataType>

DataTypeCirQueue<DataType>::GetQueue()

{

      if(rear==front)throw"下溢";

      i=(front+1)%QueueSize;                 //注意不要给队头指针赋值

      returndata[i];

}

(5)   
判空操作

循环队列的判空操作只需要判定front==rear是否成立。如果成立,则队列为空,返回1;如果不成立,则队列非空,返回0。

3.2.3 队列的链式存储结构及实现

链队列:队列的链式存储结构称为链队列。

链队列的实现

template <class DataType>

class LinkQueue

{

public:

      LinkQueue();                    //构造函数,初始化一个空的链队列

      ~LinkQueue();                   //析构函数,释放链队列中各结点的存储空间

      voidEnQueue(DataType x);       //入队操作,将元素x入队

      DataTypeDeQueue();             //出队操作,将队头元素出队

      DataTypeGetQueue();            //取链队列的队头元素

      intEmpty(){front==rear?return 1: return 0;}//判断链队列是否为空

private:

      Node<DataType>*front, *rear;   //队头和队尾指针,分别指向头结点和终端结点

};

(1)   
构造函数

template <class DataType>

LinkQueue<DataType>::LinkQueue()

{

      Node<DataType>*s=NULL;

      s=newNode<DataType>;s->next=NULL;//创建一个头结点

      front=rear=s;                     //将队头指针队尾指针都指向头结点s

}

(2)   
析构函数

template <class DataType>

LinkQueue<DataType>::~LinkQueue()

{

      Node<DataType>*p=NULL;

      while(front!=NULL)

      {

           p=front->next;

           deletefront;

           front=p;

      }

}

(3)入队操作

template <class DataType>

voidLinkQueue<DataType>::EnQueue(DataType x)

{

      Node<DataType>*s=NULL;

      s=newNode<DataType>;s->data=x;//申请一个数据域为x的结点s

      s->next=NULL;

      rear->next=s;                  //将结点s插入到队尾

      rear=s;

}

(4)出队操作

template <class DataType>

DataTypeLinkQueue<DataType>::DeQueue()

{

      Node<DataType>*p=NULL;

      intx;

      if(rear==front)throw"下溢";

      p=front->next;x=p->data;//暂存队头元素

      front->next=p->next;    //将队头元素所在结点摘链

      if(p->next==NULL)rear=front;//判断出队前队列长度是否为1

      deletep;

      returnx;

}

(5)读取

template <class DataType>

DataTypeLinkQueue<DataType>::GetQueue()

{

      if(front!=rear)

           returnfront->next->data;

}

template <class DataType>::Empty()

{

      if(front==rear)

           return1;

      else

           return0;

}

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息