数据结构基础笔记

目录
第三章 栈和队列
3.1 栈
3.1.1 栈的逻辑结构
3.1.2 栈的顺序存储结构及实现
3.1.3 栈的链式存储结构及实现
3.1.4 栈的应用举例
3.2 队列
3.4.1 队列的逻辑结构
3.4.2 队列的链式存储结构及实现
3.4.3 队列的顺序存储结构及实现
3.4.4 循环队列和链队列的比较
两种特殊的线性表——栈、队列

➢从数据结构角度看,栈和队列是操作受限的线性表,他们的逻辑结构相同

3.1 栈
3.1.1 栈的逻辑结构
栈:限定仅在 表尾进行插入和删除操作的线性表

空栈:不含任何数据元素的栈

允许插入和删除的一端称为栈顶(表尾),另一端称为栈底

栈只是对表插入和删除操作的位置进行了限制,并没有限定何时进行插入和删除操作

3.1.2 栈的顺序存储结构及实现
顺序栈——栈的顺序存储结构

如何改造数组实现栈的顺序存储:

确定用数组的哪一端表示栈底(表头)
附设指针top指示栈顶元素的下一个位置
进栈:top+1 出栈:top-1 栈空:top=base 栈满:top-base=stacksize
进栈时先压栈再top+1,即*S.top++ = e;

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>                    //bool(布尔类型的头文件) 

//定義初始容量和增量
#define FIRST 2
#define ADD 5
#define LEN sizeof(int)
using namespace std;
typedef struct Stack{
    int *base;
    int *top;
    int stacksize;
}stack;
//封裝菜單欄
void Menu(){
    cout<<"--------順序棧--------"<<endl;
    cout<<"-----1.初始化棧-------"<<endl;
    cout<<"-----2.清空棧---------"<<endl;
    cout<<"-----3.銷毀棧---------"<<endl;
    cout<<"-----4.棧判空---------"<<endl;
    cout<<"-----5.求棧的長度-----"<<endl;
    cout<<"-----6.獲取棧頂元素---"<<endl;
    cout<<"-----7.插入一個元素---"<<endl;
    cout<<"-----8.刪除一個元素---"<<endl;
    cout<<"-----9.輸出所以元素---"<<endl;
    cout<<"-----10.進制轉換------"<<endl;
    cout<<"-----11.批量入棧-------"<<endl;
    cout<<"----------------------"<<endl;

//初始化棧
bool InitStack(stack &s) {
    s.base=(int *)malloc(FIRST * LEN);
    if(!s.base){
        cout<<"存儲空間分配失敗!"<<endl;
        return false;
    }
    s.top=s.base;
    s.stacksize=FIRST;
    return true;
}
//清空棧
int Clear(stack &s){
    s.top=s.base;

//銷毀棧
int Destory(stack &s){
    delete s.base;
    s.stacksize=0;
    s.base=s.top=NULL;    

//棧判空
int Empty(stack &s){
    if(s.top==s.base){
        return 0;
    }
    return -1;
}
//獲取棧頂元素
int Gettop(stack &s){
    return *(s.top-1);

//獲取棧的長度
int Length(stack &s){
    int count;
    int *p=s.base;
    while(p!=s.top){
        count++;
        p++;
    }
    return count;

//入棧操作
void Pushone(stack &s,int e){
    //滿棧 
    if(s.top-s.base==s.stacksize){
        s.base=(int*)realloc(s.base,(s.stacksize+ADD)*LEN);
        s.top=s.base+s.stacksize;
        s.stacksize=s.stacksize+ADD;
    }
    *s.top=e; 
    s.top++;

//出棧操作 
int Popone(stack &s){
    if(s.top=s.base){
        return -1;
    } 
    s.top--;
    int e = *s.top;
    return e;
}
//打印所有元素
void Show(stack s){
    cout<<"棧底:"<<endl;
    int *p = s.base;
    while(p!=s.top){
        cout<<*p<<endl;
        p++;
    }

//進制
int Result(int a,int x){
    int c,m=0,s[100];
    while (a!=0)//数制转换,结果存入数组s[m]
    {
        c=a%x;
        a=a/x;
        m++;s[m]=c;   //将余数按顺序存入数组s[m]中
    }
    for(int k=m;k>=1;k--)//输出转换后的序列
    {
        if(s[k]>=10) //若为十六进制等则输出相相应的字母
            cout<<(char)(s[k]+55);
        else         //否则直接输出数字
            cout<<s[k];
    }


//進制轉換
void Change(stack &s,int x){
    //依次轉換棧中的元素
    int *p=s.base;
    while(p!=s.top){
        *p=Result(*p,x);
        cout<<endl; 
        p++;
    }
}
//批量輸入 
void AddSome(stack &s){
    int e;
    while(true){
        cout<<"請輸入一個要入棧的元素(輸入-1退出)"<<endl;
        cin>>e;
        if(e==-1){
            break;
        }
        Pushone(s,e);
    }
}
int main(){
    int n;
    stack s;
    while(true){
        Menu();
        cout<<"請輸入功能序號:"<<endl;
        cin>>n;
        switch(n){
            case 1:{
                InitStack(s);
                cout<<"初始化棧成功!"<<endl;
                break;
            }
            case 2:{
                if(s.base==NULL){
                    cout<<"請先初始化棧"<<endl;
                }else{
                    Clear(s);
                    cout<<"清空棧完成!"<<endl;
                }
                break;
            }
            case 3:{
                if(s.base==NULL){
                    cout<<"請先初始化棧"<<endl;
                }else{
                    Destory(s);
                    cout<<"銷毀棧完成!"<<endl;    
                }
                break;
            }
            case 4:{
                if(s.base==NULL){
                    cout<<"請先初始化棧"<<endl;
                }else{
                    if(Empty(s)==0){
                    cout<<"該棧爲空!"<<endl;
                    }else{
                        cout<<"該棧不爲空!"<<endl;
                    } 
                }
                break;
            }
            case 5:{
                if(s.base==NULL){
                    cout<<"請先初始化棧"<<endl;
                }else{
                    cout<<"棧的長度為:"<<Length(s)<<endl; 
                }
                break;
            } 
            case 6:{
                if(s.base==NULL){
                    cout<<"請先初始化棧"<<endl;
                    break;
                }else{
                    cout<<"棧頂元素為:"<<Gettop(s)<<endl; 
                }
                break;
            }
            case 7:{
                if(s.base==NULL){
                    cout<<"請先初始化棧"<<endl;
                    break;
                }else{
                    cout<<"請輸入要插入的元素!"<<endl; 
                    int e;cin>>e;
                    Pushone(s,e); 
                    cout<<"添加元素成功!"<<endl;
                }
                break;
            }
            case 8:{
                if(s.base==NULL){
                    cout<<"請先初始化棧"<<endl;
                    break;
                }else{ 
                if(Popone(s)==-1){
                    cout<<"該棧已爲空!"<<endl; 
                    break;
                }
                    cout<<"出棧成功!出棧的元素為:"<<Popone(s)<<endl; 
                }
                break;
            }
            case 9:{
                if(s.base==NULL){
                    cout<<"請先初始化棧"<<endl;
                    break;
                }else{ 
                    Show(s);
                }
                break;
            }
            case 10:{
                if(s.base==NULL){
                    cout<<"請先初始化棧"<<endl;
                    break;
                }else{ 
                    cout<<"請輸入要轉換的進制:";
                    int x;cin>>x;
                    Change(s,x);
                }
                break;
            }
            case 11:{
                if(!s.base){
                    cout<<"請先初始化棧"<<endl;
                }else{
                    AddSome(s);
                }
                break;
            } 
        }
        system("pause");
        system("cls");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261

j.chen-wang.com
99dej.com
changgek.com
jx9g.com
jx6c.com
jx5f.com
px5f.com
px3a.com
px6h.com
jx5h.com

3.1.3 栈的链式存储结构及实现
将链头作为栈顶,方便操作,且链栈不需要附设头结点

链栈的实现——插入:

Push(){
    p = (NODE*)malloc(m);
    if(!p){上溢}else{
        p->data = x;
        p->link = top;    //在表头进行插入
        top = p;
    }
}
1
2
3
4
5
6
7
8
链栈的实现——删除:

Pop(){
    if(top == NULL){下溢}else{
        x = top->data;
        p = top;
        top = top->link;
        free(p);
    }
}
1
2
3
4
5
6
7
8
链栈的实现:

#include<stdio.h>
#include<stdbool.h>
#include<malloc.h>

typedef int elementype;

typedef struct node{
    elementype data;
    struct node *next;
}stacknode, *linkstackptr;

typedef struct stack{
    linkstackptr top;        //栈顶指针 
    int count;                //计数器 
}Linkstack;
/* 若栈S为空栈,则返回TRUE,否则返回FALSE */
int stackempty(Linkstack S)

        if (S.count == 0)
                return 1;
        else
                return 0;
}
bool push(Linkstack *S, elementype e)        //入栈操作 
{
    linkstackptr s = (linkstackptr)malloc(sizeof(stacknode));
    s -> data = e;
    s -> next = S -> top;        //把当前的栈顶赋值给新的元素的后继(指针的指向)
    S -> top = s;        //新的节点赋值给栈顶指针(即让新元素成为栈顶元素)
    S -> count++;
    return true; 
}wap.ihain.cn/thread-205285154-1-1.html
wap.ihain.cn/thread-205284815-1-1.html
wap.ihain.cn/thread-205284728-1-1.html
wap.ihain.cn/thread-205284665-1-1.html
wap.ihain.cn/thread-205284377-1-1.html
wap.ihain.cn/thread-205284304-1-1.html
wap.ihain.cn/thread-205284203-1-1.html
int pop(Linkstack *s, elementype *e)        //出栈操作
{
    linkstackptr p;        //临时节点
    if(stackempty(*s))
        return 0;
    else
    {
        *e = s -> top -> data;
        p = s -> top;        //将栈顶指针交给p 
        s -> top = s -> top -> next;    //使得栈顶指针下移一位
        free(p);        //因为节点被删除,所以要释放临时节点        
        s -> count--;            //计数器减一个 
        return 1;
    }    
}
void visit(elementype p)
{
    printf("%d ", p);
}
bool traversestack(Linkstack s)
{
    linkstackptr p;
    p = s.top;
    while(p)
    {
        visit(p -> data);
        p = p -> next;
    }
    printf("\n");
    return true;
}
/*  构造一个空栈S */
bool InitStack(Linkstack *S)

        S -> top = (linkstackptr)malloc(sizeof(stacknode));
        if(!S -> top)
                return false;
        S -> top = NULL;
        S -> count = 0;
        return true;
}
/* 把S置为空栈 */
bool ClearStack(Linkstack *S)

        linkstackptr p,q;
        p = S -> top;
        while(p)
        {  
                q = p;
                p = p -> next;
                free(q);        //对每一个节点进行释放 
        } 
        S -> count = 0;
        return true;
}

/* 返回S的元素个数,即栈的长度 */
int StackLength(Linkstack S)

        return S.count;
}

/* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
int GetTop(Linkstack S,elementype *e)
{
        if (S.top == NULL)
                return 0;
        else
                *e = S.top -> data;
        return 1;
}

int main()
{
        int j;
        Linkstack s;
        int e;
        if(InitStack(&s) == true)
                for(j = 1;j <= 10;j++)
                        push(&s,j);
        printf("栈中元素依次为:");
        traversestack(s);
        pop(&s,&e);
        printf("弹出的栈顶元素 e=%d\n",e);
        printf("栈空否:%d(1:空 0:否)\n",stackempty(s));
        GetTop(s,&e);
        printf("栈顶元素 e=%d 栈的长度为%d\n",e,StackLength(s));
        ClearStack(&s);
        printf("清空栈后,栈空否:%d(1:空 0:否)\n",stackempty(s));
        
        return 0;
}
————————————————
版权声明:本文为CSDN博主「佰无一用是书生」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44614524/article/details/86745291
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
关于链栈的说明:

链栈不必设头结点,因为栈顶(表头)的操作十分频繁
采用链栈存储方式,可以使多个栈共享空间,当栈中元素个数变化较大,且存在多个栈的情况下,链栈是栈的首选存储方式
顺序栈与链栈的比较:

时间性能:顺序栈与链栈的时间性能相同,都为O(1)

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

3.1.4 栈的应用举例
一、数制转换

假设待转换的十进制数为N,转化后的数制为d,则:用d不断的去除待转换数的十进制证书N,直到商为0为止,如何将各次取得的余数,以最后一次的余数为d进制数的最高位数,依次排序即得到所求的d进制数

数制转换算法描述:

void conversion(){
    InitStack(S);    //构造空栈
    scanf("%d",&N);    //输入原十进制数N
    while(true){
        Push(S,N%8);    //将每次除8的余数进行入栈
        N=N/8;        
    }
    while(!StackEmpty(S)){
        Pop(S,e);    //将栈内数据进行出栈并输出
        printf("%d",e);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
二、括号匹配检验

在文字处理软件或编译程序时,尝尝需要检查一个表达式中的括号是否相匹配

算法思想:从左至右扫描一个表达式,则每个右括号与最近遇到的左括号存放到栈中,每当遇到一个右括号是,就将它与栈顶的左括号相匹配,同时从栈顶删除该括号

算法步骤:

初始化一个空栈
当读到左括号时,左括号进栈
当读到右括号时,从栈中出来一个元素,与当前右括号进行匹配,如果匹配成功则继续读入,否则匹配失败,返回错误信息
表达式扫描结束时若栈空,则匹配全部正确,否则表面左括号有剩余
3.2 队列
3.4.1 队列的逻辑结构
队列:只允许在一端进行插入操作,而另一端进行删除操作的线性表

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

队列的操作特性:先进先出FIFO

3.4.2 队列的链式存储结构及实现
实例:

#include<iostream>
#include<stdlib.h>
using namespace std;
//结点结构:数据域+指针域 
typedef struct QNode{
    int date;
    struct QNode *next;
}QNode,*QueuePtr;
//队列结构:队头指针+队尾指针1 
typedef struct{
    QueuePtr front;
    QueuePtr rear;
}LinkQueue;
//封裝菜單欄
void Menu(){
    cout<<"---------链队列---------"<<endl;
    cout<<"-----1.初始化队列-------"<<endl;
    cout<<"-----2.销毁队列---------"<<endl;
    cout<<"-----3.清空队列---------"<<endl;
    cout<<"-----4.队列判空---------"<<endl;
    cout<<"-----5.求队列的長度-----"<<endl;
    cout<<"-----6.獲取队头元素-----"<<endl;
    cout<<"-----7.插入一個元素---"<<endl;
    cout<<"-----8.刪除一個元素---"<<endl;
    cout<<"-----9.輸出所有元素---"<<endl;
    cout<<"-----10.批量入棧-------"<<endl;
    cout<<"----------------------"<<endl;
} wap.ihain.cn/thread-205285863-1-1.html
wap.ihain.cn/thread-205285754-1-1.html
wap.ihain.cn/thread-205285673-1-1.html
wap.ihain.cn/thread-205285565-1-1.html
wap.ihain.cn/thread-205285488-1-1.html
wap.ihain.cn/thread-205285439-1-1.html
wap.ihain.cn/thread-205285353-1-1.html
//1.初始化队列
void InitQueue(LinkQueue &Q)
{
    //初始化一个空队列时队头指针和队尾指针指向头结点 
    Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));    //为头结点分配内存空间 
    Q.front->next=NULL; //使队头指针指空,表示队列结束 
}
//2.销毁队列
void DestroyQueue(LinkQueue &Q)
{
    //销毁队列的实质:将头指针不断向后指,然后释放所指结点的内存空间
    //最后指空头尾指针 
    QueuePtr q = Q.front;
    //当q还存在时执行循环 
    while(q){
        Q.front=Q.front->next;
        free(q);
        q=Q.front;
    }
    Q.front=NULL;
    Q.rear=NULL; 
}
//3.清空队列
void ClearQueue(LinkQueue &Q)
{
    //清空队列的实质:从头结点之后的结点开始依次释放直到队尾
    QueuePtr q = Q.front,p; 
    while(p){
        p=q->next;
        free(p);
        q=p->next;
    }
    Q.front=Q.rear;
//    QueuePtr p,q;
//    p=q=Q.front->next;
//    while(p)
//    {
//        Q.front->next=p->next;
//        p=p->next;
//        free(q);
//        q=p;
//    }
//    Q.front=Q.rear;
 } 
 //4.队列判空
 int QueueEmpty(LinkQueue Q)
 {
     if(Q.front==Q.rear)
     {
         return 0;
     }else{
         return 1;
     }
 }
 //5.求队列长度
 int QueueLength(LinkQueue Q)
 {
     int count=0;
     QueuePtr p=Q.front;
     while(p!=Q.rear)
     {
         count++;
         p=p->next;
     }
     return count;
 }
 //6.获取队头元素
 int GetHead(LinkQueue Q)
 {
     return Q.front->next->date; 
 }
 //7.插入一个元素
 void EnQueue(LinkQueue &Q,int e)
 {
     //先为新增结点开辟空间 
     QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
     if(!p)
     {
         cout<<"申请内存失败,请重新尝试!"<<endl;
     }
    //链队列元素入队遵守“先进先出” 
    p->date=e;
    //新结点的指针指空表示队尾 
    p->next=NULL;
    //将原队尾的指针与新增结点连接 
    Q.rear->next=p;
    Q.rear=p;
 }
 //8.删除一个元素
int DeQueue(LinkQueue &Q)
 {
     //头结点内不存储数据 
     QueuePtr p=Q.front->next;
     Q.front->next=p->next;
     int e;
     e=p->date;
     if(p==Q.rear)
     {
         Q.front=Q.rear; 
    }
    free(p);
    return e;
 }
 //9输出所有元素
 int QueueTraverse(LinkQueue Q,QueuePtr p)
 {
     return p->date;
 }
int main()
{
    LinkQueue Q;
    int which;
    while(1)
    {
        system("cls");
        Menu();
        cin>>which;
        if(which<0){
            break;
            cout<<"程序结束!"<<endl; 
        }
        switch(which)
        {
            case 1:
                InitQueue(Q);
                if(!Q.front)
                {
                    cout<<"储存分配失败,请重新操作!"<<endl;
                }else{
                    cout<<"初始化队列成功!"<<endl;
                }
                break;
            case 2:
                if(!Q.front)
                {
                    cout<<"请先初始化队列!"<<endl;
                }else{
                    DestroyQueue(Q);
                    if(!Q.front) 
                    {
                        cout<<"销毁成功!"<<endl; 
                    }
                    else
                    {
                        cout<<"销毁失败!"<<endl;
                    }
                }
                break;
            case 3:
                if(!Q.front)
                {
                    cout<<"请先初始化队列!"<<endl;
                }else{
                    if(Q.front==Q.rear)
                    {
                        cout<<"队列为空!"<<endl;
                    }else{
                        ClearQueue(Q);
                        cout<<"队列清空成功!"<<endl;
                    }
                }
                break;
            case 4:
                if(!Q.front)
                {
                    cout<<"请先初始化队列!"<<endl;
                }else{
                    if(QueueEmpty(Q))
                    {
                        cout<<"队列不为空"<<endl;
                     } else{
                         cout<<"队列为空"<<endl;
                     }
                }
                break;
            case 5:
                if(!Q.front)
                {
                    cout<<"请先初始化队列!"<<endl;
                }else{
                    cout<<"队列的长度为:"<<QueueLength(Q)<<endl;
                }
                break;
            case 6:
                if(!Q.front)
                {
                    cout<<"请先初始化队列!"<<endl;
                }else{
                    if(Q.front==Q.rear)
                    {
                        cout<<"队列为空!"<<endl;
                    }else{
                        cout<<"队头元素为:"<<GetHead(Q)<<endl; 
                    } 
                }
                break;
            case 7:
                if(!Q.front)
                {
                    cout<<"请先初始化队列!"<<endl;
                }else{
                    int e;
                    cout<<"请输入你要插入的元素:"<<endl;
                    cin>>e;
                    EnQueue(Q,e);
                    cout<<"元素入队成功!"<<endl;
                }
                break;
            case 8:
                if(!Q.front)
                {
                    cout<<"请先初始化队列!"<<endl;
                }else{
                    if(Q.front==Q.rear)
                    {
                        cout<<"队列为空!"<<endl;
                    }
                    else
                    {
                        DeQueue(Q);
                        cout<<"元素出队成功!"<<endl;
                     } 
                }
                break;
            case 9:
                if(!Q.front)
                {
                    cout<<"请先初始化队列!"<<endl;
                }else{
                    QueuePtr q=Q.front;
                    cout<<"队列元素:";
                    while(q!=Q.rear)
                    {
                        q=q->next;
                        cout<<QueueTraverse(Q,q)<<" ";
                    }
                    cout<<endl;
                }
                break;
            default:
                cout<<"请输入正确的数字"<<endl;
                break;
        }
        system("pause");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
3.4.3 队列的顺序存储结构及实现
改造数组实现队列的顺序存储:要求队列的元素存储在数组中连续的位置,设置队头尾两个指针

入队出队的时间性能仍为O(1)


整个队列向数组下标较大方向移动:单向移动性

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

解决假溢出问题:

循环队列:将存储数组的数组头尾相接

循环队列的实现:

入队:sq[rear] = x; rear = (rear+1)%M;

出队:x = sq[front]; front = (front+1)%M

队空队满的临界条件:front=rear / front=rear(一致)

确定不同的队空队满判定条件:

附设一个存储队列中元素个数的变量,以此来判定队空队满
修改队满条件,即浪费一个元素空间,当队满时数组中只有一个空闲单元
设置标志flag,当front=rear且flag=0时为队空,当front=rear且flag=1时为队满
实例:

#include<iostream>
using  namespace std;

#define MAXSIZE  20

typedef  int ElemType;

typedef  struct
{
    ElemType data[MAXSIZE];
     int front;  /* 头指针 */
     int rear;  /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
     int count;  //元素个数
} SqQueue;

bool InitQueue(SqQueue &Sq)
{
    cout <<  "Init Queue ..." << endl;
    Sq.front =  0;
    Sq.rear =  0;
    Sq.count =  0;
     return  true;
}

bool ClearQueue(SqQueue &Sq)
{
    cout <<  "Clear Queue ..." << endl;
    Sq.front =  0;
    Sq.rear =  0;
    Sq.count =  0;
     return  true;
}

bool QueueEmpty(SqQueue &Sq)
{
     return Sq.count ==  0;  /* 队列空的标志 */
}

bool QueueFull(SqQueue &Sq)
{
     return Sq.count == MAXSIZE;
}

int QueueLength(SqQueue &Sq)
{
     if (QueueFull(Sq))
         return MAXSIZE;

     /* 队列的当前长度 */
     return (Sq.rear - Sq.front + MAXSIZE) % MAXSIZE;
}
/* 返回头元素 */
bool GetHead(SqQueue &Sq, ElemType *pe)
{
     if (QueueEmpty(Sq))
         return  false;
     else
    {
        *pe = Sq.data[Sq.front];
        cout <<  "Get Head Item " << *pe << endl;
         return  true;
    }
}

bool EnQueue(SqQueue &Sq, ElemType Elem)
{
     /* 队列满 */
     if (QueueLength(Sq) == MAXSIZE)
         return  false;
    cout <<  "EnQueue Item " << Elem << endl;
    Sq.data[Sq.rear] = Elem; /* 将元素赋值给队尾 */
    Sq.rear = (Sq.rear +  1) % MAXSIZE; /* rear指针向后移一位置, */
     /* 若到最后则转到数组头部 */
    Sq.count++;
     return  true;
}

bool DeQueue(SqQueue &Sq, ElemType *pe)
{
     if (QueueEmpty(Sq))
         return  false;
    *pe = Sq.data[Sq.front]; /* 将队头元素赋值给*pe */
    cout <<  "DeQueue Item " << *pe << endl;
    Sq.front = (Sq.front +  1) % MAXSIZE; /* front指针向后移一位置, */
     /* 若到最后则转到数组头部 */

    Sq.count--;
     return  true;
}

bool QueueTraverse(SqQueue &Sq)
{
     if (QueueEmpty(Sq))
    {
        cout <<  "Queue is empty" << endl;
         return  false;
    }

    cout <<  "Queue Traverse ..." << endl;
     for ( int i =  0;  i < Sq.count; i++)
        cout << Sq.data[i + Sq.front] <<  ' ';
    cout << endl;
     return  true;
}

int main( void)
{
    SqQueue Sq;
    InitQueue(Sq);
     for ( int i =  0; i <  20; i++)
        EnQueue(Sq, i);
    QueueTraverse(Sq);
     if (!QueueEmpty(Sq))
        cout <<  "Queue Length: " << QueueLength(Sq) << endl;
     int result;
    GetHead(Sq, &result);
    DeQueue(Sq, &result);
    DeQueue(Sq, &result);
     if (!QueueEmpty(Sq))
        cout <<  "Queue Length: " << QueueLength(Sq) << endl;
    QueueTraverse(Sq);

     return  0;
}
————————————————
版权声明:本文为CSDN博主「s1mba」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jnu_simba/article/details/8841657
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
3.4.4 循环队列和链队列的比较
时间性能:循环队列和链队列的基本操作都需要常数时间O(1)

空间性能:

循环队列:必须预先确定一个固定的长度,所以有存储元素个数的限制和空间浪费问题
链队列:没有队满的问题,只有当内存没有可用空间时才会出现队满,但是每个元素都需要一个指针域,从而产生了结构性开销
线性表、栈与队列的异同点:

相同点:逻辑结构相同,都是线性的,都可以用顺序存储结构或链式存储结构,栈和队列是两种特殊的线性表,即操作受限的线性表(只是对插入、删除运算加以限制)

不同点:

运算规则不同:线性表为随机存取,而栈只允许在一端进行插入和删除操作,因而是后进先出LIFO;队列是指允许一端进行插入、一端进行删除运算,因而是先进先出FIFO
用途不同:线性表比较通用,堆栈用于函数调用、递归和简化设计等;队列用于离散事件模拟、多道作业处理和简化设计等
练习:

1.若已知一个栈的入栈顺序为1,2,3…n,其输出序列为p1,p2…pn,则pi为:n-i+1

2.某队列允许在其两端进行入队操作,

但仅允许在一端进行出队操作,若元素a, b, c, d, e依次入此队列后再进行出队操作,则不可能得到的出队序列是 ( )

A. b, a, c, d, e B. d, b, a, c, e

C. d, b, c, a, e D. e, c, b, a, d

答:C

3.用链接方式存储的队列,在进行删除运算时:头尾指针可能都要修改

4.数组Q【n】用来表示一个循环队列,f为当前队列头元素的前一位置,r为队尾元素的位置,假定队列中的元素个数小于n,计算你队列中元素的公式为:(n+r-f)%n

5.循环队列存储在数组A[0…m]中,则入队时的操作为:rear = (rear + 1)%(m + 1)

6.循环队列放在一维数组A[0…M-1]中,end1指向队头元素,end2指向队尾元素,假设队列两段均可进行入队和出队操作,队列中最多能容纳M-1个元素,判断1队空和队满的条件:队空:end1 == end2;队满:end1 == (end2 +1)mod M

7.对于不同的使用者,一个表结构既可以是栈、也可以是队列,还可以是线性表
————————————————
版权声明:本文为CSDN博主「ErrorError!」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_50587771/article/details/121649873

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值