栈和队列实现和实例分析

article/2025/9/7 6:45:36

目录

  • 前言
  • 队列
  • 实例分析
  • 结语

前言

本篇文章主要讲述数据结构中栈和队列的实现,以及相关实例分析。

注意本文所讲述的栈是数据结构的一种,并不是内存划区中的栈区,但是这两者有相似之处,即:存储数据时满足数据先进后出的特点,除此之外还有以下特点:
(1)访问栈时,只能访问栈顶数据,要想访问栈底数据,需将栈顶数据一步步移除;
(2)栈不支持随机访问和随机插入;
通过图形表达如下:
在这里插入图片描述
数据只能从一端进入,从一端走出,要想获得栈底的数据就必须将上面的数据移除,同时是无法获取栈中间的数据的。
鉴于栈的特点,我觉得通过顺序表实现是最方便的,以下是实现代码:

//stack.h
#pragma once
#include<assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;		// 栈顶int capacity;  // 容量 
}Stack;
// 初始化栈 
void StackInit(Stack* ps);
// 入栈 
void StackPush(Stack* ps, STDataType data);
// 出栈 
void StackPop(Stack* ps);
// 获取栈顶元素 
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数 
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps);
// 销毁栈 
void StackDestroy(Stack* ps);
//stack.c
#define _CRT_SECURE_NO_WARNINGS
#include "stack.h"
void StackInit(Stack* ps)
{assert(ps);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}
void StackPush(Stack* ps, STDataType data)
{assert(ps);if (ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 2 : ps->capacity * 2;STDataType* pa = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));if (pa == NULL){perror("malloc fail");exit(-1);}ps->a = pa;ps->capacity = newcapacity;}ps->a[ps->top] = data;ps->top++;
}
void StackPop(Stack* ps)
{assert(ps);assert(!StackEmpty(ps));ps->top--;
}
bool StackEmpty(Stack* ps)
{assert(ps);return ps->top == 0;
}
STDataType StackTop(Stack* ps)
{assert(ps);assert(!StackEmpty(ps));return ps->a[ps->top - 1];
}
void StackDestroy(Stack* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->top = 0;
}
int StackSize(Stack* ps)
{assert(ps);return ps->top;
}
//test.c
#define _CRT_SECURE_NO_WARNINGS
#include "stack.h"
void test1()
{Stack ps;StackInit(&ps);StackPush(&ps, 1);StackPush(&ps, 2);printf("%d\n", StackSize(&ps));printf("%d ", StackTop(&ps));StackPop(&ps);StackPush(&ps, 3);printf("%d ", StackTop(&ps));StackPop(&ps);StackPush(&ps, 4);while (!StackEmpty(&ps)){printf("%d ", StackTop(&ps));StackPop(&ps);}printf("\n%d", StackSize(&ps));StackDestroy(&ps);
}
int main()
{test1();return 0;
}

队列

队列存储数据的方式和栈刚好相反,满足先进先出的原则,通过图形表达如下:
在这里插入图片描述
队列数据从一端进入,从另一端走出,先进入队列的数据先出,同样的无法访问队列中间的数据,但是队列可以访问队首和队尾的数据。
了解完特点,鉴于需要头部删除,尾部插入,个人觉得链表更适合模拟实现,接下来模拟实现,代码如下:

//queue.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
//数据类型
typedef int QDataType;
//队列的每个节点
typedef struct QListNode
{struct QListNode* next;QDataType data;
}QNode;// 队列的结构 
typedef struct Queue
{QNode* front;QNode* back;
}Queue;// 初始化队列 
void QueueInit(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);
//queue.c
#define _CRT_SECURE_NO_WARNINGS
#include "Queue.h"
void QueueInit(Queue* q)
{assert(q);q->back = q->front = NULL;
}
void QueuePush(Queue* q, QDataType data)
{assert(q);QNode* pa = (QNode*)malloc(sizeof(QNode));if (pa == NULL){perror("malloc fail");exit(-1);}pa->data = data;pa->next = NULL;if (q->front == NULL){q->back = q->front = pa;}else{q->back->next = pa;q->back = pa;}
}
void QueuePop(Queue* q)
{assert(q);assert(!QueueEmpty(q));QNode* del = q->front;q->front = q->front->next;free(del);del = NULL;
}
bool QueueEmpty(Queue* q)
{assert(q);return q->front == NULL;
}
QDataType QueueFront(Queue* q)
{assert(q);assert(!QueueEmpty(q));return q->front->data;
}
QDataType QueueBack(Queue* q)
{assert(q);assert(!QueueEmpty(q));return q->back->data;
}
int QueueSize(Queue* q)
{assert(q);int count = 0;QNode* cur = q->front;while (cur){count++;cur = cur->next;}return count;
}
void QueueDestroy(Queue* q)
{assert(q);QNode* cur = q->front;while (cur){QNode* del = cur;cur = cur->next;free(del);}cur = NULL;q->back = q->front = NULL;
}
//test.c
#define _CRT_SECURE_NO_WARNINGS
#include "Queue.h"
void test()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);//printf("%d ", QueueFront(&q));//QueuePop(&q);QueuePush(&q, 4);QueuePush(&q, 5);printf("\n%d\n", QueueSize(&q));while (!QueueEmpty(&q)){printf("%d ", QueueFront(&q));QueuePop(&q);}//QueuePop(&q);QueueDestroy(&q);
}
int main()
{test();return 0;
}

以上就是栈和队列的实现,实现方法只是个人觉得更合适,当然还有其他的实现方法,比如通过链表实现栈(插入删除数据就用头插头删),顺序表实现队列(这里就需要不停的挪动数据了)等,接下来通过实例来感受栈和队列的特点和如何互相实现对方的。

实例分析

  1. 用队列实现栈
    这道题设计栈的方法是通过两个队列来实现的,那么如何实现呢?
    通过上文我们知道了栈的性质,现在假如有两个队列,如下所示:
    在这里插入图片描述
    假设数据先存储在队列1中,当我们需要弹出数据时,按照栈后进先出的特性,我们需要先将队列1尾部数据之前的所有数据存储在队列2中,然后弹出队列1的数据,如图:
    在这里插入图片描述
    那我们还需要弹出数据该怎么做呢,一样的,先将队列2尾部数据之前的所有数据先挪动到队列1中,然后弹出队列2的数据,就像这样:
    在这里插入图片描述
    如此反复,直至两个队列都为空队列说明数据已全部弹出,接下来就是代码实现:
typedef int QDataType;typedef struct QListNode
{struct QListNode* next;QDataType data;
}QNode;// 队列的结构 
typedef struct Queue
{QNode* front;QNode* back;
}Queue;// 初始化队列 
void QueueInit(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);void QueueInit(Queue* q)
{assert(q);q->back = q->front = NULL;
}
void QueuePush(Queue* q, QDataType data)
{assert(q);QNode* pa = (QNode*)malloc(sizeof(QNode));if (pa == NULL){perror("malloc fail");exit(-1);}pa->data = data;pa->next = NULL;if (q->front == NULL){q->back = q->front = pa;}else{q->back->next = pa;q->back = pa;}
}
void QueuePop(Queue* q)
{assert(q);assert(!QueueEmpty(q));QNode* del = q->front;q->front = q->front->next;free(del);del = NULL;
}
bool QueueEmpty(Queue* q)
{assert(q);return q->front == NULL;
}
QDataType QueueFront(Queue* q)
{assert(q);assert(!QueueEmpty(q));return q->front->data;
}
QDataType QueueBack(Queue* q)
{assert(q);assert(!QueueEmpty(q));return q->back->data;
}
int QueueSize(Queue* q)
{assert(q);int count = 0;QNode* cur = q->front;while (cur){count++;cur = cur->next;}return count;
}
void QueueDestroy(Queue* q)
{assert(q);QNode* cur = q->front;while (cur){QNode* del = cur;cur = cur->next;free(del);}cur = NULL;q->back = q->front = NULL;
}
//上述是队列的实现
//结构体栈(该栈通过两个队列实现)
typedef struct {Queue Q1;Queue Q2;
} MyStack;MyStack* myStackCreate() {//为栈创建空间MyStack* obj = (MyStack*)malloc(sizeof(MyStack));//既然有两个队列,那我们就需要分别创建空间QueueInit(&obj->Q1);QueueInit(&obj->Q2);return obj;
}void myStackPush(MyStack* obj, int x) {assert(obj);//数据往非空的队列插入if(QueueEmpty(&obj->Q1)){QueuePush(&obj->Q2, x);}else{QueuePush(&obj->Q1, x);}
}bool myStackEmpty(MyStack* obj) {assert(obj);//栈为空,则两个队列均为空return QueueEmpty(&obj->Q1) && QueueEmpty(&obj->Q2);
}int myStackPop(MyStack* obj) {assert(obj);//栈为空不可以删除assert(!myStackEmpty(obj));//将非空队列尾数据之前的所有数据挪动到空队列,然后弹出这个尾数据Queue* empty = &obj->Q1;Queue* noempty = &obj->Q2;if(QueueEmpty(&obj->Q2)){empty = &obj->Q2;noempty = &obj->Q1;}while(QueueSize(noempty)>1){QueuePush(empty, QueueFront(noempty));QueuePop(noempty);}QDataType ret = QueueFront(noempty);QueuePop(noempty);return ret;
}int myStackTop(MyStack* obj) {assert(obj);//栈为空则没有数据assert(!myStackEmpty(obj));Queue* empty = &obj->Q1;Queue* noempty = &obj->Q2;if(QueueEmpty(&obj->Q2)){empty = &obj->Q2;noempty = &obj->Q1;}//返回的是非空队列的尾数据return QueueBack(noempty);
}void myStackFree(MyStack* obj) {
//释放不仅要释放结构体栈,还要释放其包含的两个队列QueueDestroy(&obj->Q1);QueueDestroy(&obj->Q2);free(obj);
}

由于C语言没有提供队列的实现,所以我们调用队列时需要自己实现,关于怎么实现我已在上面介绍过,这里我就直接用了。
2.用栈实现队列
同样的这里需要用两个栈来实现队列,栈的特性是后进先出,那么如何模拟出先进先出呢?我们通过图来表达:
在这里插入图片描述
这里我们将两个栈分别规定一下,假设一个栈专门用于存储数据为A,另一个专门用于弹出数据为B,当我们需要弹出数据时,先判断B队列是否为空,不为空就可以出栈,为空就需要栈A将所有的数据全部导入栈B中,入后出栈,如此就可以实现队列的先进先出了,如下图所示:
在这里插入图片描述
值得注意的是,这里当栈B不为空时,是不可以将栈A中的数据挪动到栈B中的,接下来就是代码实现(由于C语言不带栈的实现,所以需要自己实现):

// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;		// 栈顶int capacity;  // 容量 
}Stack;
// 初始化栈 
void StackInit(Stack* ps);
// 入栈 
void StackPush(Stack* ps, STDataType data);
// 出栈 
void StackPop(Stack* ps);
// 获取栈顶元素 
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数 
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps);
// 销毁栈 
void StackDestroy(Stack* ps);void StackInit(Stack* ps)
{assert(ps);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}
void StackPush(Stack* ps, STDataType data)
{assert(ps);if (ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 2 : ps->capacity * 2;STDataType* pa = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));if (pa == NULL){perror("malloc fail");exit(-1);}ps->a = pa;ps->capacity = newcapacity;}ps->a[ps->top] = data;ps->top++;
}
void StackPop(Stack* ps)
{assert(ps);assert(!StackEmpty(ps));ps->top--;
}
bool StackEmpty(Stack* ps)
{assert(ps);return ps->top == 0;
}
STDataType StackTop(Stack* ps)
{assert(ps);assert(!StackEmpty(ps));return ps->a[ps->top - 1];
}
void StackDestroy(Stack* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->top = 0;
}
int StackSize(Stack* ps)
{assert(ps);return ps->top;
}
//上述是实现栈
//结构体队列(包含两个栈)
typedef struct {Stack in;Stack out;
} MyQueue;MyQueue* myQueueCreate() {//为队列开辟空间MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));assert(obj);//为队列包含的两个栈开辟空间StackInit(&obj->in);StackInit(&obj->out);return obj;
}void myQueuePush(MyQueue* obj, int x) {assert(obj);//往栈A存储数据StackPush(&obj->in, x);
}bool myQueueEmpty(MyQueue* obj) {return StackEmpty(&obj->in) && StackEmpty(&obj->out);
}int myQueuePop(MyQueue* obj) {assert(obj);//队列为空不可以删除assert(!myQueueEmpty(obj));//出队列的数据就是栈B栈顶的数据if(StackEmpty(&obj->out)){while(!StackEmpty(&obj->in)){StackPush(&obj->out, StackTop(&obj->in));StackPop(&obj->in);}}int ret = StackTop(&obj->out);StackPop(&obj->out);return ret;
}
//队列队尾的数据就是栈A栈顶的数据
int myQueuePeek(MyQueue* obj) {assert(obj);assert(!myQueueEmpty(obj));if(StackEmpty(&obj->out)){while(!StackEmpty(&obj->in)){StackPush(&obj->out, StackTop(&obj->in));StackPop(&obj->in);}}return StackTop(&obj->out);
}void myQueueFree(MyQueue* obj) {
//释放空间要完全StackDestroy(&obj->in);StackDestroy(&obj->out);free(obj);
}

3.设计循环队列
要实现循环队列,我们需要先知道什么是循环队列。循环队列就是在逻辑上是闭环的,形如下图:
在这里插入图片描述
由于在内存地址上是不可能循环的,所以我们需要通过设计来实现循环,解决这回个问题有两个思路:(1)循环链表,利用我们之前是先过的双向循环链表实现(2)用顺序表实现;这两个方法都可以,那么我在这里通过顺序表来实现循环队列。实现过程中,我们需要注意的是什么时候队列满了,什么时候队列为空,首先我们需要两个指针分别指向首尾,如下图所示:
在这里插入图片描述

我们向内存申请k+1个空间,然后把数据插入到back指针所指向的位置,然后back++,当back++等于head时说明循环队列已满,当back等于head时说明队列为空,有了思路代码实现就容易了起来:

//匿名结构体,将队列首地址,首尾下表,顺序表长度k+1封装
typedef struct {int* Queue;int head;int back;int size;
} MyCircularQueue;
//创造循环队列
MyCircularQueue* myCircularQueueCreate(int k) {
//创建队列MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//为顺序表申请空间,空间大小为k+1obj->Queue = (int*)malloc((k+1)*sizeof(int));obj->head = obj->back = 0;obj->size = k+1;return obj;
}bool myCircularQueueIsFull(MyCircularQueue* obj) {assert(obj);//首尾指针相等就为空,这里取模原因在于避免back超出顺序表的范围,预防越界访问return (obj->back+1) % obj->size == obj->head;
}bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {assert(obj);if(myCircularQueueIsFull(obj)){return 0;}obj->Queue[obj->back] = value;obj->back++;//避免back超出顺序表的范围obj->back %= obj->size;return 1;
}bool myCircularQueueIsEmpty(MyCircularQueue* obj) {assert(obj);//循环队列为空即首尾指针相等return obj->head == obj->back;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {assert(obj);if(myCircularQueueIsEmpty(obj)){return 0;}obj->head++;//避免head超出顺序表的范围obj->head %= obj->size;return 1;
}int myCircularQueueFront(MyCircularQueue* obj) {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}return obj->Queue[obj->head];
}int myCircularQueueRear(MyCircularQueue* obj) {assert(obj);if(myCircularQueueIsEmpty(obj)){return -1;}//队尾的数据一般情况是back-1位置的数据,但在back==0时,需要特殊处理,让back-1等于k,此时(back-1+size)%size刚好满足使用return obj->Queue[(obj->back-1+obj->size)%obj->size];
}void myCircularQueueFree(MyCircularQueue* obj) {
//要完全释放空间free(obj->Queue);free(obj);
}

结语

以上就是本篇文章的全部内容了,通过三个实例充分的展示了栈和队列的实现方法是很多种的,同时关于巧用取模操作也是值得我们学习的。


http://chatgpt.dhexx.cn/article/rbq74fh8.shtml

相关文章

栈和队列的共同处和不同处

共同处 栈和队列的共同处是&#xff1a;它们都是由几个数据特性相同的元素组成的有限序列&#xff0c;也就是所谓的线性表。 不同处 队列 队列&#xff08;queue&#xff09;是限定仅在表的一端插入元素、在另一端删除元素的线性表。 在队列中&#xff0c;允许插入的一端被…

索引的优缺点以及索引的设计原则

索引概述 索引&#xff08;index&#xff09; 是帮助 MySQL 高效获取数据的数据结构&#xff08;有序&#xff09;。 在数据之外&#xff0c;数据库系统还维护者满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&#xff08;指向&#xff09;数据&#xff0…

SQL数据库之索引优缺点

SQL数据库之索引使用原则及利弊 索引是对数据库表中一列或多列的值进行排序的一种结构&#xff0c;使用索引可快速访问数据库表中的特定信息。 优点 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。 可以大大加快数据的检索速度&#xff0c;这也是创建…

Oracle索引的建立及优缺点

在看公司建表语句时发现了这样一段代码 本着学习的态度面向百度&#xff1a;&#xff1a;&#xff1a;&#xff1a;&#xff1a; 原来这是Oracle的索引 Oracle的索引说明 1&#xff09;索引是数据库对象之一&#xff0c;用于加快数据的检索&#xff0c;类似于书籍的索引。在…

MySQL索引的优缺点

MySQL 中的索引简介 1、索引的优点 为什么要创建索引&#xff1f;这是因为&#xff0c;创建索引可以大大提高系统的查询性能。 第一、通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。 第二、可以大大加快数据的检索速度&#xff0c;这也是创建索引的最…

MySQL索引的使用知识有哪些?

面试造火箭&#xff0c;工作拧螺丝&#xff0c;虽然工作时我们都在使用基本的 sql&#xff0c;但是不好意思&#xff0c;面试 90% 都在问原理&#xff0c;例如索引&#xff0c;锁&#xff0c;日志&#xff0c;引擎啊等等。 在关系数据库中&#xff0c;索引是一种单独的、物理的…

索引的数据结构与优缺点

1、索引的数据结构 什么是索引&#xff1f; 索引就是mysql为了提高查询数据的一种数据结构。在数据之外&#xff0c;数据库系统还维护着满足特定查找算法 的数据结构&#xff0c;这些数据结构以某种方式引用(指向)数据&#xff0c;这样就可以在这些数据结构上实现高级查找 算法…

Oracle 数据库:ORA-12541: TNS: 无监听程序 的解决办法

路径下D:\app\ou\product\11.2.0\dbhome_1\NETWORK\ADMIN host后面地址全改为 " HOSTlocalhost " 。 以上两个配置文件修改完成后&#xff0c;Win R 在弹出框中输入 " SERVICES.MSC " &#xff0c;找到Oracle的服务&#xff08;OracleService&#xff09;…

ora12541+tns-01153未能处理字符串

操作系统&#xff1a; windows2008 数据库&#xff1a;oracle11g 数据库运行中突然连接不上 ora12541TNS:无监听程序 数据库服务器端查看&#xff1a; 使用dos端sqlplus登录正常 重启Oracle服务依然无法登陆 ora12541TNS plsql无法连接 使用 lsnrctl status 查看监听状态…

plsql远程访问数据库 解决 ora12170TNS 连接超时,ora-12541:TNS:无监听程序

自己在虚机linux安装了o12版本后&#xff0c;计划通过wins主机通过plsql操作oracle&#xff0c; 结果没有顺利链接&#xff0c;plsql报错 排错步骤: 1.查看网络是否通畅 打开cmd, ping 数据库IP 2. 查看端口是否通畅 打开cmd,tnsping 数据库IP 如果piing不通,可能是防火墙问…

ora-12541

描述&#xff1a;oracle 19c plsql登录报错 原因&#xff1a;修改了服务器的名称为ods 解决&#xff1a;修改listener.ora&#xff0c;tnsnames.ora文件中服务器名为ods&#xff0c;重启监听即可

oracle数据库只能用127.0.0.1和localhost登录,用ip无法登陆,提示ora12541监听错误解决办法

这些修改都在oracle安装完成后的服务端文件中修改&#xff0c;客户端里面的监听文件默认是没有的&#xff0c;也不需要配置 oracle服务端&#xff0c;客户端安装完成后&#xff0c; 服务端监听文件 E:\app\Administrator\product\11.2.0\dbhome_1\NETWORK\ADMIN\listener.or…

Oracle ORA12514 监听程序当前无法识别连接描述符中请求的服务

最简单的有可能是你的服务还没有开启&#xff0c;需要启动服务&#xff01;&#xff01;&#xff01;&#xff01; 在连接数据库的时候&#xff0c;有时会遇到一个“ORA12514&#xff1a;监听程序当前无法识别连接描述符中请求的服务”的错误&#xff0c;这个错误其实就是数据…

使用Navicat连接Oracle数据库及ORA-12541: TNS: 无监听程序、ORA-28547:connection to server failed、ORA-12514:TNS报错解决方案

1、Navicat的安装请参考:图形化界面之Navicat Premium 12 的安装与使用_蓝多多的小仓库的博客-CSDN博客_navicat premium12使用 2、打开Navicat,选择连接--->Oracle 3、配置常规和高级选项 这里服务名请参考: 为了避免后续存在权限问题,这里角色选择SYSDBA: 4、各项…

oracle报错ORA-12514

问题&#xff1a;oracle使用服务名orcl登录不成功&#xff0c;并且报错 ORA-12514, TNS:listener does not currently know of service requested in conn原因分析&#xff1a; ORA-12514 错误通常表示 Oracle 数据库监听器无法识别客户端请求的服务名称。这可能是由于以下原因…

Oracle ORA-12541的处理

Oracle ORA-12541的处理 Lsnrctl status Lsnrctl start 尝试链接进去sqlplus xxx/xxx198.126.12.3/fpd ps -ef | grep pmon 确定实例没有打开 查看数据库日志的停库原因 发现数据库日志是被截断的&#xff0c;数据库日志被截断一般是系统冗机的问题 那就直接startup开库 因…

连接linux数据库Oracle时报错ORA-12541: TNS: 无监听程序重启后提示出现ORA-01034和ORA-27101

1 windows上安装Oracle的客户端。 2 确保linux服务器上的1521端口开放 3 看你的window机器是够能够ping同linux服务器的ip地址 4 在windows中的Oracle客户端的tnsnames.ora里添加你要连接的Oracle&#xff08;即虚拟里Linux的Oracle&#xff09;信息。 5 虚拟机linux打开Or…

ORA-12541:TNS:无监听程序

最近很郁闷&#xff0c;本人电脑上安装了oracle11g,每次关机再开机后登录PL/SQL DEVELOPER都提示ora-12541无监听程序&#xff0c;网上找了半天&#xff0c;重新配置listener.ora,tnsnames.ora,可是还是不行&#xff0c;通过在dos命令窗口重启监听就好了&#xff0c;有没有网友…

ORA-12541:TNS:no listener

PLSQL作为一个专门开发面向Oracle数据库的应用&#xff0c;那登录时肯定和Oracle息息相关了。那面对出现“ORA-12541:TNS:no listener”时应该怎么办呢&#xff1f;我分为了三个步骤&#xff1a;“确保Oracle连接成功”和“Oracle的Net Configuration Assistant的配置”和“重新…

ORA-12541: TNS: 无监听程序 的解决办法

今天好好的&#xff0c;突然有用户报系统登录不了了&#xff0c;经过排查问题出在Oracle&#xff0c;报ORA-12541: TNS: 无监听程序&#xff0c;先是重新服务不行&#xff0c;然后重新配置监听还不行&#xff0c;最后上网查了一下&#xff0c;结果是是它的问题哈&#xff0c;就…