今天学习了数据结构中栈,队列的知识

  相对于单链表来说,栈和队列就是添加的方式不同,队列就相当于排队,先排队的先出来(FIFO),而栈就相当于弹夹,先压进去的子弹后出来(FILO)。

首先看一下栈(Stack)的实现

 #include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALES 0
typedef struct NODE
{
int i;
struct NODE *pNext; //指向的是 上一个从栈顶刚压入的结点
}Stack;
typedef int BOOL; //因为c语言里没有布尔类型,所以用int模拟一下
void Push(Stack **pTop,int i);
BOOL IfEmpty(Stack *pTop);
Stack *Pop(Stack **pTop); //出栈操作
int main()
{
Stack *pTop = NULL; }
void Push(Stack **pTop,int i) //压栈操作
{
Stack *pTemp = (Stack *)malloc(sizeof(Stack));
pTemp->i = i;
pTemp->pNext = NULL; pTemp->pNext = *pTop;
*pTop = pTemp; return;
}
BOOL IfEmpty(Stack *pTop) //因为c++的STL容器里存在判断栈是否为空的操作,在这模拟一下
{
if(pTop == NULL)
return TRUE;
return FALES;
}
Stack *Pop(Stack **pTop)
{
Stack *pPop = NULL;
if(IfEmpty(*pTop))
{
return NULL;
}
else
{
pPop = *pTop;
*pTop = (*pTop)->pNext;
return pPop;
}
}

其次队列(Queue)的实现非常简单,队列压入的实现就和单链表尾添加一样,而弹出就和单链表头删除是一样的,只不过不需要free直接返回队首指针即可;

 #include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
typedef struct NODE
{
int i;
struct NODE *pNext;
}Queue;
typedef int BOOL;
int GetId();
void QueueIn(Queue **ppHead,Queue **ppEnd);
BOOL IfEmpty(Queue *pHead);
Queue *QueueOut(Queue **ppHead,Queue **ppEnd);
int main()
{
Queue *pHead = NULL;
Queue *pEnd = NULL;
Queue *p = NULL; QueueIn(&pHead,&pEnd);
QueueIn(&pHead,&pEnd);
QueueIn(&pHead,&pEnd);
p = QueueOut(&pHead,&pEnd); return ; }
int GetId()
{
static int i = ;
i++;
return i;
}
void QueueIn(Queue **ppHead,Queue **ppEnd)
{
Queue *pTemp = (Queue *)malloc(sizeof(Queue));
pTemp->i = GetId();
pTemp->pNext = NULL; if(*ppHead == NULL)
{
*ppHead = pTemp;
}
else
{
(*ppEnd)->pNext = pTemp;
}
*ppEnd = pTemp;
}
BOOL IfEmpty(Queue *pHead)
{
if(pHead == NULL)
return TRUE;
return FALSE;
}
Queue *QueueOut(Queue **ppHead,Queue **ppEnd)
{
Queue *pOut = NULL;
if(IfEmpty(*ppHead) == TRUE)
return NULL;
else
{
pOut = *ppHead;
*ppHead = (*ppHead)->pNext;
return pOut;
}
}

那么栈和栈区又有什么区别呢?先看这样一段程序

 #include<stdio.h>
int main()
{
  int i = 1;
  printf("%d %d\n ",i,i++);   return ;
}

可能一打眼看 就认为是1  1,但测试后发现是 2  1,这就不免让人联想到先进后出的特点了,由于printf是一个标准输出库函数,i 和 i++都算做是两个实参,在函数中,形参也是一个局部变量,在函数这个堆区中存在,按照图中出栈的顺序先B后A,那么先 i++ 出来为 1 ,i 其次出来就为2了(启示就是,在栈区中 若一个函数的参数用了同一个变量 ,记得栈的特点)

双向链表,故名思意就是有一个链表可正向可反向,也就是在添加每个结点的时候,加入一个指针,指向上一个结点的地址,代码如下:

 #include<stdio.h>
#include<stdlib.h>
typedef struct NODE
{
int id;
struct NODE *pNext;
struct NODE *pLast; //指向上个结点
}List;
void AddNode(List **ppHead,List **ppEnd,int id);
int main()
{
List *pHead = NULL;
List *pEnd = NULL;
AddNode(&pHead,&pEnd,);
AddNode(&pHead,&pEnd,);
AddNode(&pHead,&pEnd,);
AddNode(&pHead,&pEnd,); while(pHead)
{
printf("%d\n",pHead->id);
pHead = pHead->pNext;
}
printf("\n"); while(pEnd)
{
printf("%d\n",pEnd->id);
pEnd = pEnd->pLast;
} }
void AddNode(List **ppHead,List **ppEnd,int id)
{
List *pTemp = (List *)malloc(sizeof(List));
pTemp->id = id;
pTemp->pLast = NULL;
pTemp->pNext = NULL; if(*ppHead == NULL)
{
*ppHead = pTemp;
*ppEnd = pTemp;
}
else
{
(*ppEnd)->pNext = pTemp;
pTemp->pLast = *ppEnd;
*ppEnd = pTemp;
}
return;
}

最后看到了有两个小问题

第一个 如何用两个栈实现一个队列  这个很简单,先全部压入第一个栈里,然后弹出再压出第二个栈里,最后弹出的就是队列的顺序,反反得正

 #include<stdio.h>
#include<stdlib.h>
typedef struct NODE
{
int id;
struct NODE *pNext;
}
Stack;
void Push1(Stack **pTop1);
Stack *Pop1(Stack **pTop1);
void Push2(Stack **pTop2,Stack *pNode);
Stack *Pop2(Stack **pTop2);
Stack *QueueOut(Stack **pTop1,Stack **pTop2);
void InitStack(Stack **pTop1,int n);
int IfEmpty(Stack *pTop1);
int GetId();
int main()
{
Stack *pTop1 = NULL;
Stack *pTop2;
Stack *pTemp = NULL;
InitStack(&pTop1,);
pTemp = QueueOut(&pTop1,&pTop2);
while(pTop2)
{
pTemp = QueueOut(&pTop1,&pTop2);
} return ;
}
int GetId()
{
static int i = ;
i++;
return i;
}
void InitStack(Stack **pTop1,int n)
{
int i;
for(i = ;i < n;i++)
{
Push1(pTop1);
}
return;
}
void Push1(Stack **pTop1)
{
Stack *pTemp = (Stack *)malloc(sizeof(Stack));
pTemp->id = GetId();
pTemp->pNext = NULL; pTemp->pNext = *pTop1;
*pTop1 = pTemp; return;
}
Stack *Pop1(Stack **pTop1)
{
Stack *pPop = NULL;
if(*pTop1 == NULL)
{
return NULL;
}
else
{
pPop = *pTop1;
*pTop1 = (*pTop1)->pNext;
return pPop;
}
}
void Push2(Stack **pTop2,Stack *pNode)
{
pNode->pNext = *pTop2;
*pTop2 = pNode; return; }
Stack *Pop2(Stack **pTop2)
{
Stack *pPop = NULL;
if(*pTop2 == NULL)
{
return NULL;
}
else
{
pPop = *pTop2;
*pTop2 = (*pTop2)->pNext;
return pPop;
}
}
int IfEmpty(Stack *pTop1)
{
if(pTop1 == NULL)
return ;
return ;
}
Stack *QueueOut(Stack **pTop1,Stack **pTop2)
{
while(IfEmpty(*pTop1) != )
Push2(pTop2,Pop1(pTop1)); return Pop2(pTop2);
}

第二个,如何快速的找到链表里倒数第n个结点,设置两个指针指向头,一个先往后走k个结点,然后一起走,当先走的那个到达尾结点时,后走的也就是倒数第k个结点了

 #include<stdio.h>
#include<stdlib.h>
typedef struct NODE
{
int id;
struct NODE *pNext;
}List;
int GetId();
void AddNode(List **ppHead,List **ppEnd);
List *Search(List *pHead,List *pEnd,int n);
int main()
{
List *pHead = NULL;
List *pEnd = NULL;
List *pTemp = NULL;
int i;
for(i = ;i < ;i++)
AddNode(&pHead,&pEnd);
pTemp = Search(pHead,pEnd,);
printf("%d\n",pTemp->id); }
int GetId()
{
static int i = ;
i++;
return i;
}
void AddNode(List **ppHead,List **ppEnd)
{
List *pTemp = (List *)malloc(sizeof(List));
pTemp->id = GetId();
pTemp->pNext = NULL; if(*ppHead == NULL)
{
*ppHead = pTemp;
}
else
{
(*ppEnd)->pNext = pTemp; }
*ppEnd = pTemp;
}
List *Search(List *pHead,List *pEnd,int n)
{
int i;
List *pFast = pHead;
List *pSlow = pHead;
for(i = ;i < n;i++)
{
pFast = pFast->pNext;
}
while(pFast)
{
pSlow = pSlow->pNext;
pFast = pFast->pNext;
}
return pSlow; }

2019-04-29 22:32:52 编程菜鸟自我反省,大佬勿喷,谢谢!!!

4-29 c语言之栈,队列,双向链表的更多相关文章

  1. C语言实现,队列可伸缩

    两个栈实现一个队列,C语言实现,队列可伸缩,容纳任意数目的元素. 一.思路:1.创建两个空栈A和B:2.A栈作为队列的入口,B栈作为队列的出口:3.入队列操作:即是入栈A:4.出队列操作:若栈B为空, ...

  2. C语言函数调用栈

    C语言函数调用栈 栈溢出(stack overflow)是最常见的二进制漏洞,在介绍栈溢出之前,我们首先需要了解函数调用栈. 函数调用栈是一块连续的用来保存函数运行状态的内存区域,调用函数(calle ...

  3. Leetcode栈&队列

    Leetcode栈&队列 232.用栈实现队列 题干: 思路: 栈是FILO,队列是FIFO,所以如果要用栈实现队列,目的就是要栈实现一个FIFO的特性. 具体实现方法可以理解为,准备两个栈, ...

  4. java 集合 Connection 栈 队列 及一些常用

    集合家族图 ---|Collection: 单列集合 ---|List: 有存储顺序 , 可重复 ---|ArrayList: 数组实现 , 查找快 , 增删慢 ---|LinkedList: 链表实 ...

  5. Java 容器之 Connection栈队列及一些常用

    集合家族图 ---|Collection: 单列集合 ---|List: 有存储顺序 , 可重复 ---|ArrayList: 数组实现 , 查找快 , 增删慢 ---|LinkedList: 链表实 ...

  6. java面向对象的栈 队列 优先级队列的比较

    栈 队列 有序队列数据结构的生命周期比那些数据库类型的结构(比如链表,树)要短得多.在程序操作执行期间他们才被创建,通常用他们去执行某项特殊的任务:当完成任务之后,他们就会被销毁.这三个数据结构还有一 ...

  7. C++实现一个简单的双栈队列

    双栈队列的原理是用两个栈结构模拟一个队列, 一个栈A模拟队尾, 入队的元素全部压入此栈, 另一个栈B模拟队首, 出队时将栈A的元素弹入栈B, 将栈B的栈顶元素弹出 此结构类似汉诺塔, 非常经典, 这里 ...

  8. 栈&队列&并查集&哈希表(julyedu网课整理)

    date: 2018-11-25 08:31:30 updated: 2018-11-25 08:31:30 栈&队列&并查集&哈希表(julyedu网课整理) 栈和队列 1. ...

  9. 《数据结构与算法分析:C语言描述》复习——第三章“线性表、栈和队列”——双向链表

    2014.06.14 20:17 简介: 双向链表是LRU Cache中要用到的基本结构,每个链表节点左右分别指向上一个和下一个节点,能够自由地左右遍历. 图示: 实现: // My implemen ...

随机推荐

  1. mysql慢查询----pt-query-digest详解慢查询日志(linux系统)

    一.简介 pt-query-digest是用于分析mysql慢查询的一个工具,它可以分析binlog.General log.slowlog,也可以通过SHOWPROCESSLIST或者通过tcpdu ...

  2. scrapy初探(一)-斗鱼TV直播信息抓取

    由于有相关需求,最近两天开始学了一下scrapy 这次我们就以爬取斗鱼直播间为例,我们准备爬取斗鱼所有的在线直播信息, 包括1.主播昵称 2.直播领域 3.所在页面数 4.直播观看人数 5.直播间ur ...

  3. 基于sklearn和keras的数据切分与交叉验证

    在训练深度学习模型的时候,通常将数据集切分为训练集和验证集.Keras提供了两种评估模型性能的方法: 使用自动切分的验证集 使用手动切分的验证集 一.自动切分 在Keras中,可以从数据集中切分出一部 ...

  4. erlang工作总结

    总结下自己在做erlang的经验 1.不管什么样的情况下,一定要关注好函数的返回值再来使用,不知道返回值盲目的使用的话,不仅不能达到目标,而且不存在代码/报错提醒.得不偿失. 2.构思好自己的想法,定 ...

  5. Linux装agent

    解压Linux.zip  Linux的负载机链接:https://pan.baidu.com/s/1yrmsT3PYfuL9Wlh4FEYxaA 密码:s72n unzip Linux.zip chm ...

  6. 19/03/17Python笔记

    一.判断元素是否为数字 ".isdigit() #判断123是不是数字,是的话输出True,不是输出False 二.标志位 需要死循环时,不一定用 while True 还可以用 while ...

  7. vim粘贴缩进问题

    vim不支持直接从其他应用复制内容粘贴过来,而是模拟用户键盘输入来实现的,一般设置vim在换行时自动以上一行的的缩进为初始位置,这样就会导致复制过来的内容出现缩进错乱. set paste 解决粘贴乱 ...

  8. Oracle的导入和导出

    导出命令: EXP 用户名/密码@数据库名  BUFFER=64000 file=G:\dmp\full1.dmp  OWNER=用户名 导入命令: IMP 用户名/密码@数据库名 BUFFER=64 ...

  9. 日期date出参入参和timestamp转化

    日期传到form页面,注意MM要大写 由于Date在MySQL没有默认值,没有设置的时候,会自动变成0000-00-00,影响渲染到Java类中,所以需要在程序中设置默认值 date转timestam ...

  10. WPF项目中解决ConfigurationManager不能用(转)

    https://blog.csdn.net/MOESECSDN/article/details/78107888 在WPF项目中遇到这样的问题,做一下笔记.希望对自己和读者都有帮助. 在aap.con ...