链栈和链队的基本实现

学完顺序结构的知识,有些小激动,这些知识还是挺简单的,要知道栈是先进后出,队是先进先出。算法是为了解决问题。栈和队列作为两种特殊的线性表,一定有它存在的道理。(我也不太了解用在哪些地方)

链栈

C++代码

这里可能有些疑惑的地方应该是结点的设置,看看书是咋说的。

/*****************************
链栈类LinkStack的类定义
******************************/
template
struct Node
{
DataType data; //数据域
Node *next; //指针域
};
​
template
class LinkStack
{
public:
LinkStack( ); //构造函数,初始化一个空链栈
~LinkStack( ); //析构函数,释放链栈各结点的存储空间
void Push(DataType x); //入栈操作,将元素x入栈
DataType Pop( ); //出栈操作,将栈顶元素出栈
DataType GetTop( ); //取栈顶元素(并不删除)
int Empty( ); //判空操作,判断链栈是否为空栈
private:
Node *top; //栈顶指针即链栈的头指针
};
​
/*******************************
链栈类LinkStack的入栈操作
********************************/
template
void LinkStack :: Push(DataType x)
{
Node *s = nullptr;
s = new Node; s->data = x; //申请结点s数据域为x
s->next = top; top = s; //将结点s插在栈顶
}
​
/*******************************
链栈类LinkStack的出栈操作
********************************/
template
DataType LinkStack :: Pop( )
{
Node *p = nullptr;
DataType x;
if (top == nullptr) throw "下溢";
x = top->data; p = top; //暂存栈顶元素
top = top->next; //将栈顶结点摘链
delete p;
return x;
}
​
/*******************************
链栈类LinkStack的取栈顶操作
********************************/
template
DataType LinkStack :: GetTop()
{
if(top == nullptr)
throw "下溢异常";
else
return top->data;
}
​
/*******************************
链栈类LinkStack的判空操作
********************************/
template
int LinkStack :: Empty()
{
if(top == nullptr)
throw "下溢异常";
else
return 0;
}

我的使用情况:

#include <iostream>
using namespace std;
struct Node{
    int data;
    Node *next;
};
class LinkStack
{
    public:
        LinkStack(){//初始化,InitStack 
           top=NULL;
           cout<<"OK";
        };
        ~LinkStack(){//销毁栈,DestroyStack 
        top=NULL;
        cout<<"end";
        };
        void Push(int x){//入栈 
            Node * s = NULL;
            s = new Node;
            s-> data = x;
            s-> next = top;
            top = s;
            };
​
        int Pop(){//出栈 
            Node * p = NULL;
            int x;
            if(top == NULL)throw"下溢";
            x =top->data;
            p=top;
            top = top->next;
            delete p;
            return x;
        };
    private:
        Node * top;
        
};
​
int main(){
    LinkStack s;
    cout<<"将1和2入栈"<<endl; 
    s.Push(1);
    s.Push(2);
    cout<<"出栈:"<<s.Pop()<<endl; 
    cout<<"出栈:"<<s.Pop()<<endl; 
    return 0;
    
}
 

 

顺序栈和链栈的比较

  • 顺序栈和链栈基本操作的时间复杂度均为O(1),因此唯一可以比较的是空间性能。初始时顺序栈必须确定一个固定的长度,所以有存储元素个数的限制和浪费空间的问题。

  • 链栈没有栈满的问题,只有当内存没有可用空间时才会出现栈满,但是每个元素都需要一 个指针域,从而产生了结构性开销。

可以做个小总结,如果栈的使用时元素个数变化较大,建议使用链栈,其余情况可以使用顺序栈。

链队列

C++代码

#include<iostream>
using namespace std;
template <typename DataType>
struct Node
{
DataType data; //数据域
Node *next; //指针域
};
template <typename DataType>
class LinkQueue
{
public:
LinkQueue( ); //构造函数,初始化一个空的链队列
~LinkQueue( ); //析构函数,释放链队列各结点的存储空间
void EnQueue(DataType x); //入队操作,将元素x入队
DataType DeQueue( ); //出队操作,将队头元素出队
DataType GetQueue( ); //取链队列的队头元素
int Empty( ); //判断链队列是否为空
private:
Node<DataType>*front, *rear; //队头和队尾指针,分别指向头结点和终端结点
};
/*********************************
链队列类LinkQueue的构造函数
**********************************/
template <typename DataType>
LinkQueue<DataType>:: LinkQueue( )
{
Node<DataType>*s = NULL;
   s = new Node;
 s->next = NULL; //创建头结点s
front = rear = s; //将队头指针和队尾指针都指向头结点s
}
​
/*********************************
链队列类LinkQueue的析构函数
**********************************/
template <typename DataType>
LinkQueue<DataType>:: ~LinkQueue()
{
Node<DataType>*q = NULL;
while (front != NULL) //释放单链表的每一个结点的存储空间
{
q = front; //暂存被释放结点
front = front->next; // front指向被释放结点的下一个结点
delete q;
}
}
/*********************************
链队列类LinkQueue的入队操作
**********************************/
template <typename DataType>
void LinkQueue<DataType>:: EnQueue(DataType x)
{
Node<DataType>*s = NULL;
s = new Node; //申请结点s
s->data = x; s->next = NULL;
rear->next = s; rear = s; //将结点s插入到队尾
}
/*********************************
链队列类LinkQueue的出队操作
**********************************/
template <typename DataType>
DataType LinkQueue<DataType>:: DeQueue( )
{
DataType x;
Node<DataType>*p = NULL;
if (rear == front) throw "下溢";
p = front->next; x = p->data; //暂存队头元素
front->next = p->next; //将队头元素所在结点摘链
if (p->next == NULL) rear = front; //判断出队前队列长度是否为1
delete p;
return x;
}
/*********************************
链队列类LinkQueue的取队头操作
**********************************/
template <typename DataType>
DataType LinkQueue<DataType>:: GetQueue()
{
if(front == rear)
throw "下溢异常";
else
return front->next->data;
}
​
/*********************************
链队列类LinkQueue的判空操作
**********************************/
template <typename DataType>
int LinkQueue<DataType>:: Empty()
{
if(front == rear)
return 1;
else
return 0;
}
 

我的使用情况:

#include<iostream>
using namespace std;
struct Node
{
int data; //数据域
Node *next; //指针域
};
template <typename DataType>
class LinkQueue
{
public:
LinkQueue( ); 
~LinkQueue( ); 
void EnQueue(DataType x); 
DataType DeQueue( ); 
DataType GetQueue( );
int Empty( ); 
private:
Node*front, *rear; 
};
​
template <typename DataType>
LinkQueue<DataType>:: LinkQueue( )
{
Node*s = NULL;
   s = new Node;
 s->next = NULL; //创建头结点s
front = rear = s; //将队头指针和队尾指针都指向头结点s
}
​
​
template <typename DataType>
LinkQueue<DataType>:: ~LinkQueue()
{
Node*q = NULL;
while (front != NULL) //释放单链表的每一个结点的存储空间
{
q = front; //暂存被释放结点
front = front->next; // front指向被释放结点的下一个结点
delete q;
}
}
​
template <typename DataType>
void LinkQueue<DataType>:: EnQueue(DataType x)
{
Node*s = NULL;
s = new Node; //申请结点s
s->data = x; s->next = NULL;
rear->next = s; rear = s; //将结点s插入到队尾
}
​
template <typename DataType>
DataType LinkQueue<DataType>:: DeQueue( )
{
DataType x;
Node*p = NULL;
if (rear == front) throw "下溢";
p = front->next; x = p->data; //暂存队头元素
front->next = p->next; //将队头元素所在结点摘链
if (p->next == NULL) rear = front; //判断出队前队列长度是否为1
delete p;
return x;
}
​
template <typename DataType>
DataType LinkQueue<DataType>:: GetQueue()
{
if(front == rear)
throw "下溢异常";
else
return front->next->data;
}
​
​
template <typename DataType>
int LinkQueue<DataType>:: Empty()
{
if(front == rear)
return 1;
else
return 0;
}
​
int main( )
{
int x;
LinkQueue<int>Q; //定义对象变量Q
cout << "对5和8执行入队操作,";
Q.EnQueue(5); Q.EnQueue(8);
cout << "当前队头元素为:" << Q.GetQueue( ) << endl; //输出队头元素5
​
try
{
x = Q.DeQueue( );
cout << "执行一次出队操作,出队元素是:" << x << endl; //输出出队元素5
} catch(char* str){
cout << str << endl;
}
​
try
{
cout << "请输入入队元素:";
cin >> x;
Q.EnQueue(x);
} catch(char* str){
cout << str << endl;
}
cout << "当前队头元素为:" << Q.GetQueue( ) << endl; //输出队头元素8
try
{
x = Q.DeQueue( );
cout << "执行一次出队操作,出队元素是:" << x << endl; //输出出队元素8
} catch(char* str){
cout << str << endl;
}
​
if (Q.Empty( ) == 1) cout << "队列为空" << endl;
else cout << "队列非空" << endl; //队列有2个元素,输出队列非空
return 0;
}

循环队列和链队列的比较

循环队列和链队列基本操作的时间复杂度均为O(1),因此,可以比较的只有空间性能。

初始时循环队列必须确定一个固定的长度,所以有存储元素个数的限制和浪费空间的问题。链队列没有溢出的问题,只有当内存没有可用空间时才会出现溢出,但是每个元素都需要一个指针域,从而产生了结构性开销。

作为一般规律,当队列中元素个数变化较大时,应该采用链队列,反之,应该采用循环队列,如果确定不会发生假溢出,也可以采用顺序队列。

到这里,就结束了哦,栈和队列作为两种特殊的线性表的链式储存听懂了莫。懂了就点赞、关注吧!

参考用书: 数据结构-------从概念到C++实现(第3版)

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值