栈与队列

看C++的STL,看习惯了数据结构,不看底层实现实在是非常难受的一件事情。


数据结构的底层无非还是指针和数据单元。实现所用到的数据结构 一般为 数组/指针 配合以 指针进行的。


栈的FILO,队列的FIFO。只是挪动指针的逻辑不同,没有新的概念引入。




队列:
添加(push)的时候尾指针移动,链表尾插。


删除(POP)的时候,头指针移动,删除(*front).->next。


queue没有类似vector, list等的iterator迭代器, 所以不能够通过iterator进行遍历, 要遍历queue, 可以通过front, pop等操作进行组合...




对比数据结构:


队列:


/*队列的数据节点*/
typedef struct QNode{
    int data;
    struct QNode *next;
}QNode,*QueuePtr;         //底层实现采用了链表


/*对头队尾指针*/
typedef struct {
    QueuePtr front;
    QueuePtr rear;
}LinkQueue;   // 必须成对出现的头(front)和尾(rear)指针。








栈:
值得关注的一个点是栈的大小,数据结构如下:
typedef struct{
    int *top;
    int *base;
    int stackSize;
}SqStack;


初始化栈的时候设置栈的大小。
每次入栈,查看栈中是否还有空间。入栈top++;出栈top--; 
代码中还充分考虑了栈大小不足的时候每次的增量。


代码中可以看到: 
init:    (*S).top = (*S).base;
          (*S).stackSize = STACK_INIT_SIZE;
push: if(空间足够)  *((*S).top)++ = elem;


pop: *elem = *--((*S).top);  


这里想到一个问题,问什么栈一开始就要制定大小呢?
可以看出栈采用的是连续存储的数据结构,连续存储的数据结构第一想到了什么呢-----数组。  你要申请连续的空间,肯定是要告知大小的。不似与链表产串联碎片。
但是如果栈用链表的数据结构呢?
我的想法是,应该从功能来定位数据结构的用途,而不是不摆大环境的去看数据结构的实现。这就需要计算机的知识而不是语言算法的知识了,那位大大比较清楚,请留言告知哈。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


栈:


定义:限定仅在表尾进行插入和删除操作的线性表,因此表尾称之为栈顶,表头为栈底,重要特点是后进先出(LIFO)


这里写图片描述


操作:


InitStack(&S) 初始化一个栈
DestoryStack(&S)销毁一个已经存在的栈
ClearStack(&S)清空一个栈
StackEmpty(S)判断已存在的栈是否为空
StackLength(S)求栈长度
GetTop(S,&e)获取栈顶部元素
Push(&S,e)将一个元素e压入栈(核心)
Pop(&S,&e) 将栈顶元素出栈,并用e返回其值(核心)
实现(C语言): 
和线性表的实现类似,栈也有两种实现方式,分别为顺序栈和链栈


顺序栈的实现:


/*栈和队列的实现(C语言版)-------顺序栈*/


#include<stdio.h>
#include<malloc.h>
#include"string.h"


#define STACK_INIT_SIZE 100//栈的基础容量
#define STACK_INCREMENT 100//栈增长量


#define overflow_error 0
#define OK 1
#define operate_error 2
#define stack_null_error 3


typedef struct{
    int *top;
    int *base;
    int stackSize;
}SqStack;


/*
    初始化顺序栈
*/
int InitStack(SqStack *S){


    (*S).base = (int *)malloc(STACK_INIT_SIZE * sizeof(int));


    if( (!(*S).base) ){
        exit(overflow_error);
    }
    (*S).top = (*S).base;
    (*S).stackSize = STACK_INIT_SIZE;
    return OK;
}


/*
    入栈操作,elem为要入栈的元素
*/


int PushStack(SqStack *S,int elem){
    //如果内存不够用,则重新申请空间
    if((*S).top-(*S).base>(*S).stackSize){


        (*S).base = (int *)realloc((*S).base,((*S).stackSize+STACK_INCREMENT)*sizeof(int));
        //未申请上空间
        if(!(*S).base){
            exit(overflow_error);
        }
        (*S).top = (*S).base+(*S).stackSize;
        (*S).stackSize += STACK_INCREMENT;


    }


    *((*S).top)++ = elem;
    return OK;


}


/*出栈操作,将栈顶元素出栈,并用elem将该元素返回*/
int PopStack(SqStack *S,int *elem){
    //判断是否栈空
    if((*S).top == (*S).base){
        return stack_null_error;
    }
    *elem = *--((*S).top);//将元素弹出栈,并将指针下移
    return OK;
}






/*获取栈顶元素,但是并不是将元素出栈,并用elem返回元素值*/
int GetTop(SqStack S,int *elem){
    if(S.top == S.base){
        return stack_null_error;
    }
    *elem = *(S.top-1);
    return OK;
}




/*判断是否栈空*/
int StackEmpty(SqStack s){
    int flag = 0;
    if(s.base == s.top){
        flag = 0;
    }else{
        flag = 1;
    }


return flag;
}


/*根据操作返回的结果进行成功与否的显示*/
void Utils_Print_Msg(int flag){
    if(flag == OK){
        printf("成功\n");
    }else{
        printf("不成功\n");
    }
}








/*主函数*/
int main(){
    SqStack stack;
    //栈初始化
    int flag = InitStack(&stack);
    Utils_Print_Msg(flag);


    //入栈
    flag = operate_error;
    flag = PushStack(&stack,60);
    flag = PushStack(&stack,50);
    flag = PushStack(&stack,40);
    flag = PushStack(&stack,30);
    flag = PushStack(&stack,20);
    Utils_Print_Msg(flag);


    int getElem = 0;
    GetTop(stack,&getElem);
    printf("获取到的栈顶元素是%d\n",getElem);


    //出栈
    int elem = 0;
    flag = operate_error;
    flag = PopStack(&stack,&elem);
    if(flag == OK){
        printf("%d出栈成功\n",elem);
    }else{
        printf("%d出栈失败\n",elem);
    }


    //获取栈顶元素
    GetTop(stack,&getElem);
    printf("获取到的栈顶元素是%d\n",getElem);


return 0;
}
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
应用: 
栈的应用十分广泛,所以也产生了许多使用栈的经典应用算法,几个简单的用用的简单实现。 
数制转换:


/*
    进制转换---除K取余法
    int Num_10 十进制下的数
    int Num_convered 要转换的的进制
*/
int Conversion(int Num_10,int Num_convered){
    SqStack s;
    InitStack(&s);
    printf("数制转换前%d\n",Num_10);
    while(Num_10){
        PushStack( &s,(Num_10%Num_convered) );
        Num_10 = Num_10/Num_convered;
    }
    printf("转换数制后");
    while(StackEmpty(s)){
        int e;
        PopStack(&s,&e);
        printf("%d",e);
    }
    printf("\n");


}


--------------------------------------
//在主函数中添加代码测试一下:
    int num_10,num_convered;
    printf("输入十进制数");
    scanf("%d",&num_10);


    printf("输入要转换的进制");
    scanf("%d",&num_convered);
    Conversion(num_10,num_convered);
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
队列: 
定义: 
队列是一种先进先出的数据结构,只允许在表的一端进行插入,在表的另一端进行删除元素。允许插入的一端叫队尾,允许删除的一端叫队头。 
这里写图片描述


操作:


InitQueue(&Q)初始化队列
DestoryQueue(&Q)销毁队列
ClearQueue(&Q)清空队列
QueueEmpty(Q)队列为空
GetHead(Q,&e)获得队首元素,并用e返回其值,但是并不出队
EnterQueue(&Q,e)将元素e入队
DeleteQueue(&Q,&e)将元素出队,并用e返回其值
实现(C语言版): 
和之前的数据结构类似,队列也有两种实现方式,为顺序队列和链队列


单链队列的实现(C语言版):


/*栈和队列的实现(C语言版)-------单链队列*/


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


#define overflow_error 0
#define OK 1
#define operate_error 2
#define queue_null_error 3


/*队列的数据节点*/
typedef struct QNode{
    int data;
    struct QNode *next;
}QNode,*QueuePtr;


/*对头队尾指针*/
typedef struct {
    QueuePtr front;
    QueuePtr rear;
}LinkQueue;


/*初始化一个单链表队列*/
int InitQueue(LinkQueue *Q){
    (*Q).front = (*Q).rear = (QueuePtr)malloc(sizeof(QNode));


    if(!(*Q).front){
        exit(overflow_error);
    }
    (*Q).front->next = NULL;
    return OK;
}


/*将元素elem入队*/
int EnterQueue(LinkQueue *Q,int elem){
    QueuePtr newNode = (QueuePtr)malloc(sizeof(QNode));
    if(!newNode){
        exit(overflow_error);
    }
    newNode->data = elem;
    newNode->next = NULL;
    (*Q).rear->next = newNode;
    (*Q).rear = newNode;


    return OK;


}


/*将队尾的元素出队,并用elem将其值返回*/
int DeleteQueue(LinkQueue *Q,int *elem){
    if((*Q).front == (*Q).rear){
        return queue_null_error;
    }


    QueuePtr deleteNode = (*Q).front->next;
    *elem = deleteNode->data;
    (*Q).front->next = deleteNode->next;


    if((*Q).rear == deleteNode){
        (*Q).rear = (*Q).front;
    }
    free(deleteNode);


    return OK;


}


/*根据操作返回的结果进行成功与否的显示*/
void Utils_Print_Msg(int flag){
    if(flag == OK){
        printf("成功\n");
    }else{
        printf("不成功\n");
    }
}








/*主函数*/
int main(){
    LinkQueue queue;
    //初始化队列
    int flag = operate_error;
    flag = InitQueue(&queue);
    Utils_Print_Msg(flag);
    //将元素elem插入队尾
    flag = operate_error;
    flag = EnterQueue(&queue,78);
    flag = EnterQueue(&queue,567);
    flag = EnterQueue(&queue,21);
    flag = EnterQueue(&queue,26);
    flag = EnterQueue(&queue,54);
    flag = EnterQueue(&queue,34);
    flag = EnterQueue(&queue,8);
    flag = EnterQueue(&queue,37);
    Utils_Print_Msg(flag);
    //将队头元素出队,并用elem将其值返回
     flag = operate_error;
     int deleteNum;
    flag = DeleteQueue(&queue,&deleteNum);
    if(flag){
        printf("%d\n",deleteNum);
    }else{
        printf("失败");
    }


    flag = DeleteQueue(&queue,&deleteNum);
    if(flag){
        printf("%d\n",deleteNum);
    }else{
        printf("失败");
    }




    flag = DeleteQueue(&queue,&deleteNum);
    if(flag){
        printf("%d\n",deleteNum);
    }else{
        printf("失败");
    }




    flag = DeleteQueue(&queue,&deleteNum);
    if(flag){
        printf("%d\n",deleteNum);
    }else{
        printf("失败");
    }


    flag = DeleteQueue(&queue,&deleteNum);
    if(flag){
        printf("%d\n",deleteNum);
    }else{
        printf("失败");
    }




return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值