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

  相对于单链表来说,栈和队列就是添加的方式不同,队列就相当于排队,先排队的先出来(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. 2017年3月30日15:00:19 fq以后的以后 动态代理

    代理与继承,组合不同的是,继承是继承父类特性,组合是拼装组合类的特性,代理是使用代理类的指定方法并可以做自定义. 静态类是应用单个类,当代理的类数量较多时可用动态代理,动态代理在概念上很好理解 htt ...

  2. java学习笔记41(数据库连接池 C3p0连接池)

    在之前的学习中,我们发现,我们需要频繁的创建连接对象,用完之后还需要在关闭资源,因为这些连接对象都是占资源的,但是又不得不创建,比较繁琐,为了解决这种情况,Java出现了数据库连接池: 数据库连接池的 ...

  3. Python 基于时间的进程通信

    import time from multiprocessing import Process,Event def f1(e): time.sleep(2) n = 100 print("子 ...

  4. 7--Python入门--条件和循环

    5.1 条件语句 条件语句基本框架如下:if 判断语句1: 执行语句块1elif 判断语句2: 执行语句块2else: 执行语句块3 a = 10 if a%2 == 0 : #这里使用了取余函数% ...

  5. Power BI中DAX的动态计算方差

    我花了一点时间试图解决一个棘手的DAX表达式,那就是如何动态计算方差,下面我们认识一下这两个函数: PARALLELPERIOD  和 SAMEPERIODLASTYEAR  它能实现我们想要的结果, ...

  6. idea快捷键的设置

    因为开始学java被培训机构里的无良老师给带偏,"染上了"MyEclipse的快捷键"恶习",于是很难改了. 所以,在使用idea时,要设置快捷键了,快点适应之 ...

  7. 测试那些事儿—postman入门介绍

    1.postman入门介绍 一款功能强大的网页调试与发送网页HTTP请求的工具. 1)模拟各种HTTP请求,如get,post,put,delete 2)测试集合Collection    Colle ...

  8. restframework细节学习

    一.后端发送列表.字典 1. 发送字典出现safe error,需要如下处理 def books(request): ll=[{},{}] # return HttpResponse(json.dum ...

  9. 编译安装和apt安装Nginx1.14.0

    安装依赖 yum -y install gcc gcc-c++yum -y install zlib zlib-devel openssl openssl-devel pcre-devel 在Ubun ...

  10. 常用http/https以及socks5代理总结

    代理 格式 # 设置http代理 export http_proxy= # 设置https代理 export HTTPS_PROXY= # 设置ftp代理 export FTP_PROXY= # 同时 ...