当前位置: 首页 > news >正文

C语言数据结构初阶(8)----栈与队列OJ题

· CSDN的uu们,大家好。这里是C语言数据结构的第八讲。
· 目标:前路坎坷,披荆斩棘,扶摇直上。
· 博客主页: @姬如祎
· 收录专栏:数据结构与算法
  1. 栈与队列的知识

点我➡➡队列相关
点我➡➡栈相关

2. 用栈实现队列

原题链接:
剑指 Offer 09. 用两个栈实现队列 - 力扣(LeetCode)
232. 用栈实现队列 - 力扣(Leetcode)
题目描述:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

2.1 思路分析

一个队列里面包含了两个栈,stack1和stack2。直讲解有点抽象,我们用一个具体的例子来讲解。

假设我们要向队列中插入,1,2,3三个元素后将它们删除,如何实现呢?

首先,我们插入1这个元素,不妨把他插入到stack1,然后再依次插入,2,3,此时stack1内栈顶元素为3,stack2为空(见下图)。

这时候,我们尝试从队列中删除一个元素。按照队列先入先出的规则,最先入列的1应该是最先出列的,故应该删除1。但是1存储在stack1中并不是在栈顶,于是我们需要借助stack2:如果我们把stack1中的元素依次弹出,并压入到stack2中,则stack2中的元素顺序正好和原来相反。因此经过三次弹出stack1和压入stack2的操作后,stack1为空,stack2中的元素是 3, 2, 1,这时候就可以弹出栈顶的1了。

在删除队头的1后,队列中还剩2和3,我们想要继续删除队头的元素,那么应该删除2,而此时2恰好又在栈顶,因此直接弹出2即可。

通过例子的分析我们就可以总结如下规律:

添加元素的步骤:直接将元素入栈到stack1即可。

删除元素的步骤:当stack2不为空时,在栈顶的元素就是队列中先入列的元素,直接弹出栈顶的元素即可;当stack2为空时,我们就需要将stack1中的元素依次弹出并压入到stack2中,直到stack1为空。如果说stack2为空,去stack1中拿元素时发现stack1也为空,根据题目要求返回-1即可。

销毁队列:销毁两个栈即可。

当然你也可以用数组模拟实现栈,进而用两个栈实现队列。

2.2 代码实现

#define INIT_STACK_SIZE 4
typedef char STDataType;typedef struct Stack
{STDataType* a;int top;int capacity;
} ST;void StackInit(ST* st)
{assert(st);st->a = (STDataType*)malloc(sizeof(STDataType) * INIT_STACK_SIZE);st->capacity = INIT_STACK_SIZE;st->top = 0;
}void StackPush(ST* st, STDataType x)
{assert(st);if (st->top == st->capacity){STDataType* new = (STDataType*)realloc(st->a, sizeof(STDataType) * st->capacity * 2);if (!new){perror("StackPush::malloc");exit(-1);}else{st->a = new;st->capacity *= 2;}}st->a[st->top] = x;st->top++;}
void StackPop(ST* st)
{assert(st);assert(st->top);st->top--;
}
bool StackEmpty(ST* st)
{assert(st);return st->top == 0;
}
STDataType StackTop(ST* st)
{assert(st);assert(st->top);return st->a[st->top - 1];
}
int StackSize(ST* st)
{assert(st);return st->top;
}
void StackDestory(ST* st)
{assert(st);free(st->a);st->a = NULL;st->capacity = 0;st->top = 0;
}typedef struct {ST pushStack;ST popStack;
} MyQueue;MyQueue* myQueueCreate() {MyQueue* queue = (MyQueue*)malloc(sizeof(MyQueue));StackInit(&queue->pushStack);StackInit(&queue->popStack);return queue;
}void myQueuePush(MyQueue* obj, int x) {StackPush(&obj->pushStack, x);
}int myQueuePop(MyQueue* obj) {if(StackEmpty(&obj->popStack)){while(!StackEmpty(&obj->pushStack)){StackPush(&obj->popStack, StackTop(&obj->pushStack));StackPop(&obj->pushStack);}}STDataType top = StackTop(&obj->popStack);StackPop(&obj->popStack);return top;
}int myQueuePeek(MyQueue* obj) {if(StackEmpty(&obj->popStack)){while(!StackEmpty(&obj->pushStack)){StackPush(&obj->popStack, StackTop(&obj->pushStack));StackPop(&obj->pushStack);}}return StackTop(&obj->popStack);
}bool myQueueEmpty(MyQueue* obj) {return StackEmpty(&obj->popStack) && StackEmpty(&obj->pushStack);
}void myQueueFree(MyQueue* obj) {StackDestory(&obj->pushStack);StackDestory(&obj->popStack);free(obj);
}

3. 用队列实现栈

原题链接:
225. 用队列实现栈 - 力扣(Leetcode)
题目描述:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppopempty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

3.1 思路分析

一个栈里面包含了两个队列,Queue1和Queue2,直接讲解也是有点抽象,我们通过例子来讲解:

假设我们要依次入栈1, 2,3

首先入栈元素1,同样,我们不妨直接把他插入Queue1中,然后再次插入2, 3到Queue1中,此时Queue1中有三个元素1, 2, 3,Queue2为空。

现在,我们尝试从栈中删除一个元素。按照栈后进先出的规则,最后入栈的元素3应该最先出栈。但是元素3并不在Queue1的队头,我们不能直接把他删除。这时候我们就要借助Queue2了:将元素1从Queue1中出列,将它入列到Queue2中;将元素2从Queue1中出列将它入列到Queue2中,此时我们会发现,要出栈的元素3就在Queue1的队头了,直接将其出列即可。

同样地,我们还想删除一个元素,此时2就是栈顶元素,它不在Queue2的队头不能直接删除,同样需要借助另一个队列Queue1,将元素1从Queue2中出列,入列到Queue1中,此时要出栈的元素2,就在Queue2的队头了,直接删除即可。

还想删除栈顶的元素1时,我们发现它就在Queue1的队头直接删除即可。

通过以上分析我们总结出一下规律:

删除元素:将不为空的那个队列数据的N-1(N为不为空的那个队列的元素个数/队列大小)个导入到为空的那个队列,剩下的那个元素即为栈顶元素,删除即可。

添加元素:将元素添加到那个不为空的队列中即可,如果两个都为空,随便添加到哪一个都行。

查看栈顶的元素:根据以上分析:不为空的那个队列队尾的数据就是栈顶的元素,我们直接查看队尾的元素即可。

判断栈是否为空:如果两个队列都为空,则栈为空,否则栈不为空。

销毁栈:销毁两个队列即可。

同样地,你也可以使用两个数组来模拟两个队列,进而模拟实现栈。

3.2 代码实现

typedef int QueueDataType;typedef struct QueueNode
{struct QueueNode* next;QueueDataType data;
} QueueNode;typedef struct Queue
{QueueNode* head;QueueNode* tail;int size;
} Queue;//队列的初始化
void QueueInit(Queue* pq)
{assert(pq);pq->head = pq->tail = NULL;pq->size = 0;
}//队列的销毁
void QueueDestory(Queue* pq)
{assert(pq);QueueNode* cur = pq->head;while (cur){QueueNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;pq->size = 0;
}//队尾增加元素
void QueuePush(Queue* pq, QueueDataType x)
{assert(pq);QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));newNode->data = x;newNode->next = NULL;if (!pq->head){pq->head = pq->tail = newNode;}else{pq->tail->next = newNode;pq->tail = newNode;}pq->size++;
}//队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);//one way//return pq->size == 0;//another wayreturn pq->head == NULL;
}//出队列
void QueuePop(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));//one possibility//if (pq->head == pq->tail)//{//    free(pq->head);//    pq->head = pq->tail = NULL;//}//else//{//    QueueNode* next = pq->head->next;//    free(pq->head);//    pq->head = next;//}//pq->size--;//another wayQueueNode* next = pq->head->next;free(pq->head);pq->head = next;pq->size--;if (pq->head == NULL)pq->tail = NULL;}//队列的元素个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}//队头元素
QueueDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}//队尾元素
QueueDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}typedef struct {Queue q1;Queue q2;
} MyStack;MyStack* myStackCreate() {MyStack* stack = (MyStack*)malloc(sizeof(MyStack));QueueInit(&stack->q1);QueueInit(&stack->q2);return stack;
}bool myStackEmpty(MyStack* obj) {return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}void myStackPush(MyStack* obj, int x) {Queue* emptyQueue = &obj->q1, *noneEmptyQueue = &obj->q2;if(QueueEmpty(&obj->q2)){emptyQueue = &obj->q2;noneEmptyQueue = &obj->q1;}QueuePush(noneEmptyQueue, x);
}int myStackPop(MyStack* obj) {Queue* emptyQueue = &obj->q1, *noneEmptyQueue = &obj->q2;if(QueueEmpty(&obj->q2)){emptyQueue = &obj->q2;noneEmptyQueue = &obj->q1;}while(QueueSize(noneEmptyQueue) > 1){QueueDataType front = QueueFront(noneEmptyQueue);QueuePop(noneEmptyQueue);QueuePush(emptyQueue, front);}QueueDataType front = QueueFront(noneEmptyQueue);QueuePop(noneEmptyQueue);return front;
}int myStackTop(MyStack* obj) {Queue* emptyQueue = &obj->q1, *noneEmptyQueue = &obj->q2;if(QueueEmpty(&obj->q2)){emptyQueue = &obj->q2;noneEmptyQueue = &obj->q1;}return QueueBack(noneEmptyQueue);
}void myStackFree(MyStack* obj) {QueueDestory(&obj->q1);QueueDestory(&obj->q2);free(obj);
}

4. 有效的括号

原题链接:
20. 有效的括号 - 力扣(Leetcode)
题目描述:
给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。

4.1 思路分析

你可能会想到用括号的数量来进行判断,但是因为题目要求每个括号都应该与对应的括号进行匹配,这种思路显然是行不通的。

那我们该怎么做呢?大致思路:我们维护一个栈,然后遍历所有的括号,如果说遇到左括号我们就把它入栈。随后继续遍历,如果遇到右括号,我们就取栈顶元素出来,与遍历到的括号类型进行匹配,如果说与栈顶的括号类型不匹配,就返回flase,如果匹配呢?就继续往下遍历。最后判断一下栈是否为空即可。如果说栈为空,所有的左括号均与右括号进行了匹配,返回true,如果栈不为空,说明左括号数量较多,返回false即可!

这里值得注意的是:如果说字符串的一开始就是右括号的类型,那么栈显然就是空,这种情况就需要我们特殊处理一下。

4.2 代码实现

#define INIT_STACK_SIZE 4
typedef char STDataType;typedef struct Stack
{STDataType* a;int top;int capacity;
} ST;void StackInit(ST* st)
{assert(st);st->a = (STDataType*)malloc(sizeof(STDataType) * INIT_STACK_SIZE);st->capacity = INIT_STACK_SIZE;st->top = 0;
}void StackPush(ST* st, STDataType x)
{assert(st);if (st->top == st->capacity){STDataType* new = (STDataType*)realloc(st->a, sizeof(STDataType) * st->capacity * 2);if (!new){perror("StackPush::malloc");exit(-1);}else{st->a = new;st->capacity *= 2;}}st->a[st->top] = x;st->top++;}
void StackPop(ST* st)
{assert(st);assert(st->top);st->top--;
}
bool StackEmpty(ST* st)
{assert(st);return st->top == 0;
}
STDataType StackTop(ST* st)
{assert(st);assert(st->top);return st->a[st->top - 1];
}
int StackSize(ST* st)
{assert(st);return st->top;
}
void StackDestory(ST* st)
{assert(st);free(st->a);st->a = NULL;st->capacity = 0;st->top = 0;
}bool isValid(char * s){if(!s)return false;ST st;StackInit(&st);int len = strlen(s);for(int i = 0; i < len; i++){if(s[i] == '(' || s[i] == '[' || s[i] == '{')StackPush(&st, s[i]);else{if(StackEmpty(&st)){StackDestory(&st);return false;}else{char top = StackTop(&st);if(top == '(' && s[i] == ')' || top == '{' && s[i] == '}' || top == '[' && s[i] == ']')StackPop(&st); else{StackDestory(&st);return false;}}}}bool isEmpty = StackEmpty(&st);StackDestory(&st);return isEmpty;
}

5. 设计循环队列

原题链接:
622. 设计循环队列 - 力扣(Leetcode)
题目描述:
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。

5.1 循环队列的基础知识

循环队列的定义:我们把队列头尾相接的顺序存储结构称为循环队列。

循环队列的逻辑结构:

大家可以看到我这里空了一个位置,至于是为什么?有什么作用?我先卖个关子!😊😊

循环队列的缺点:用数组实现的话,队列的容量随着数组定义是就已经确定啦。

循环队列的优点:增加了空间的使用效率。

5.2 数组OR链表

大家一看到循环队列的逻辑结构肯定第一想法就是用链表实现。那么用链表实现行不行呢?当然是没有问题的,但是我们肯定要经过各种比较选择出一种最优秀的方法撒!

无论用什么什么数据结构实现我们都会面临一个问题:怎么判断循环队列是否已经满了嘞?这个点在设计循环队列时是相当重要的。

对于链表也是同样的道理。那么我们该怎么解决这个问题呢?你说,我们可以一开始令rear不同head,这样就可以很好的区分循环队列空和满的状态了,或许你也可能会说:我们可以维护一个变量来记录循环队列的大小,这样也能区分循环队列空与满的状态。不错,你很厉害。

但是呢,这里还有一个方法。不妨我们一起来看看:比如我们要设计的循环队列容量为3,我们的数组就开4个整型的大小。这样做也能很好的区分循环队列空与满的状态哦!

我们看到这样设计的话当rear的下一个位置是head时就是循环队列为满的状态,当head等于rear时就是循环队列为空的时候。链表同理的哈!

那么,到底是哪种方法好呢?仁者见仁智者见智,很多书都是以这种多开一个空间的方式来设计循环队列的,我们这里就是讲解这种啦!

回到我们的正题:是链表还是数组呢?

我们来看看链表:乍一看好像没啥问题,但是注意到看到题目我们是要实现获取队尾元素的这个函数的,单向的循环链表显然找尾是非常麻烦的。你说,我们可以用双向循环链表呀!很好,没有问题。只是这样做的话,是不是有些复杂呢?

我们来看看数组:取队尾元素我们只要访问rear下标减一的位置就行,只是可能存在数组下标越界的问题,很简单我们只需要在rear加一和rear减一的过程中对结果取模就行啦!

综上所述:设计循环队列我们选用一个比循环队列容量大一的数组来实现。

5.3 函数的实现

因为在操作数据时我们要用到循环队列的容量,还要维护head,rear等变量,所以我们将它们全部封装在一个结构体里面,结构如下:

typedef struct {int front; //就是上面所有图中的head,表示队头元素int rear; //队尾元素int size; //循环队列的容量,这个一开始就是确定了的int* queue; //设计循环队列的数组
} MyCircularQueue;

MyCircularQueue(k): 构造器,设置队列长度为 k 。

这个函数我们需要把数组开辟出来,大小就是循环队列的长度加一。还需要初始化我们维护的变量。

MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* q = (MyCircularQueue*)malloc(sizeof(MyCircularQueue)); //开辟结构体q->front = q->rear = 0; //初始化front和rearq->size = k; //初始化循环队列的长度q->queue = (int*)malloc(sizeof(int) * (q->size + 1)); //初始化我们的数组return q;
}

isEmpty(): 检查循环队列是否为空。

这里我们先实现这个函数,因为下面的函数会用到这个函数。根据上面的知识,我们只需要判断rear是不是等于front就可以判断循环队列是不是为空啦!

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->front == obj->rear;
}

enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。

插入元素也比较简单,我们将rear指向的位置进行赋值,然后让rear加一就行啦!只不过需要注意的是rear加一的时候下标可能会越界,这个时候我们就需要对rear加一的值取模。

当然,如果循环队列是满的状态也是不允许插入元素的。

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if(((obj->rear + 1) % (obj->size + 1)) == obj->front) //判断循环队列是否为满也需要取模return false;else{obj->queue[obj->rear] = value;obj->rear = (obj->rear + 1) % (obj->size + 1);return true;}
}

deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。

删除元素我们只需要让front加一进行逻辑上的删除即可!当然循环队列不为空不允许删除!同时也需要对加一的结果取模!

bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return false;else{obj->front = (obj->front + 1) % (obj->size + 1);return true;}
}

Front: 从队首获取元素。如果队列为空,返回 -1 。

这个函数我们只需要返回front指向的位置就行。当然前提是循环队列不为空啦!

int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;elsereturn obj->queue[obj->front];
}

Rear: 获取队尾元素。如果队列为空,返回 -1 。

两个注意点:

1:不为空才能获取队尾元素。

2:因为rear-1才是队尾元素,所以注意取模!

int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;elsereturn obj->queue[(obj->rear - 1 + obj->size + 1) % (obj->size + 1)];
}

剩余的函数就不单独写啦!直接放到后面一起的代码实现中啦!

5.4 代码实现

typedef struct {int front; //就是上面所有图中的head,表示队头元素int rear; //队尾元素int size; //循环队列的容量,这个一开始就是确定了的int* queue; //设计循环队列的数组
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* q = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));q->front = q->rear = 0;q->size = k;q->queue = (int*)malloc(sizeof(int) * (q->size + 1));return q;
}bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->front == obj->rear;
}bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if(((obj->rear + 1) % (obj->size + 1)) == obj->front)return false;else{obj->queue[obj->rear] = value;obj->rear = (obj->rear + 1) % (obj->size + 1);return true;}
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return false;else{obj->front = (obj->front + 1) % (obj->size + 1);return true;}
}int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;elsereturn obj->queue[obj->front];
}int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;elsereturn obj->queue[(obj->rear - 1 + obj->size + 1) % (obj->size + 1)];
}bool myCircularQueueIsFull(MyCircularQueue* obj) {return ((obj->rear + 1) % (obj->size + 1)) == obj->front;
}void myCircularQueueFree(MyCircularQueue* obj) {free(obj->queue);free(obj);
}

相关文章:

C语言数据结构初阶(8)----栈与队列OJ题

CSDN的uu们&#xff0c;大家好。这里是C语言数据结构的第八讲。 目标&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;数据结构与算法栈与队列的知识点我➡➡队列相关点我➡➡栈相关2. 用栈实现队列原题链接…...

JavaScript——原型对象

JavaScript——原型对象专题 文章目录JavaScript——原型对象专题1. 原型对象2. 原型对象的this指向3. 案例4. constructor属性5. 对象原型6. 总结7. 原型继承8. 原型链由先前的学习可知&#xff0c;构造函数实例创建的对象彼此独立、互不影响&#xff0c;很好的体现了面向对象…...

网络安全 2023 年为什么如此吃香?事实原来是这样....

前言由于我国网络安全起步晚&#xff0c;所以现在网络安全工程师十分紧缺。俗话说:没有网络安全就没有国家安全为什么选择网络安全&#xff1f;十四五发展规划建议明确提出建设网络强国&#xff0c;全面加强网络安全保障体系和能力建设&#xff0c;加强网络文明建设&#xff0c…...

(源码篇02)webpack5中的事件调度系统和NormalModuleFactary核心逻辑

1. 书接上回&#xff0c;从 this.factorizeQueue.add(options, callback); 开始 不是很清楚上下文的兄弟&#xff0c;可以去看下我之前写的 &#xff08;源码篇01&#xff09;浅析webpack5中Compiler中重要的hook调用过程。 此文比较干&#xff0c;各位读者开始阅读前&#xf…...

Vue2.x源码:new Vue()做了啥?

vue源码版本vue2.5.2 new Vue()做了啥? new Vue()会执行_init方法&#xff0c;而_init方法在initMixin函数中定义。 src/core/instance/index.js文件中定义了Vue function Vue (options) {this._init(options) }initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycl…...

WinForm | C# 弹出简易的消息提示框 (仿Android Toast消息提示)

ApeForms Toast消息提示 文章目录ApeForms Toast消息提示前言方法原型及参数释义消息驻留延时消息弹出模式队列模式抢占模式复用模式UI库安装与使用获取示例源码前言 在使用手机的时候经常会见到屏幕的中下方会弹出消息提示框&#xff0c;它就是Toast&#xff0c;以下是百度百…...

1、DRF实战总结:DRF特点、序列化与RESTful API规范

Django这种基于MVC开发模式的传统框架&#xff0c;非常适合开发基于PC的传统网站&#xff0c;因为它同时包括了后端的开发(逻辑层、数据库层) 和前端的开发(如模板语言、样式)。现代网络应用Web APP或大型网站一般是一个后台&#xff0c;然后对应各种客户端(iOS, android, 浏览…...

SIP协议及其简单介绍

SIP协议及其简单介绍概述流程SIP流程两台设备建立会话原理使用场景概述 SIP&#xff08;Session Initiation Protocol&#xff0c;会话初始化协议&#xff09;是一个应用层协议&#xff0c;用于在互联网上创建、修改和终止多媒体会话。SIP是一个客户端/服务器协议&#xff0c;…...

安全防御第四天:防病毒网关

一、恶意软件1.按照传播方式分类&#xff08;1&#xff09;病毒病毒是一种基于硬件和操作系统的程序&#xff0c;具有感染和破坏能力&#xff0c;这与病毒程序的结构有关。病毒攻击的宿主程序是病毒的栖身地&#xff0c;它是病毒传播的目的地&#xff0c;又是下一次感染的出发点…...

Postman接口与压力测试实例

Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。它提供功能强大的 Web API & HTTP 请求调试。 1、环境变量和全局变量设置 环境变量可以使用在以下地方&#xff1a; URLURL paramsHeader valuesform-data/url-encoded valuesRaw body contentHelper fi…...

TCP/IP socket

## TCP Socket 收发缓冲区: 每个socket在linux内核中都有一个发送缓冲区和一个接收缓冲区。 只要对端将数据发送过来&#xff0c;linux内核TCP/IP协议栈就会负责将数据缓存到socket对应的接收缓冲区中&#xff0c;无论是否调用recv。 recv()所做的工作&#xff0c;只是把内核缓…...

“工作三年,跳槽要求涨薪50%”,合理吗?

如果问在TI行业涨工资最快的方式是什么&#xff1f;回答最多的一定是&#xff1a;跳槽&#xff01;前段时间&#xff0c;知乎上这样一条帖子引发了不少IT圈子的朋友的讨论 &#xff0c;有网友提问 “程序员跳槽要求涨薪50%过分吗&#xff1f;”截图来源于知乎&#xff0c;如侵删…...

Vue学习计划九:了解Vue动画效果以及过渡动画和动态组件的使用方法

Vue.js 是一个流行的 JavaScript 框架&#xff0c;它提供了很多工具和功能&#xff0c;可以帮助开发人员创建动态、交互式的 Web 应用程序。其中之一就是动画效果&#xff0c;Vue.js 提供了一系列的 API 和指令&#xff0c;使得添加动画效果变得非常容易。 在 Vue.js 中&#…...

【Linux】进程理解与学习Ⅲ-环境变量

环境&#xff1a;centos7.6&#xff0c;腾讯云服务器Linux文章都放在了专栏&#xff1a;【Linux】欢迎支持订阅&#x1f339;相关文章推荐&#xff1a;【Linux】冯.诺依曼体系结构与操作系统【Linux】进程理解与学习Ⅰ-进程概念浅谈Linux下的shell--BASH【Linux】进程理解与学习…...

【三】一起算法---栈:STL stack、手写栈、单调栈

纸上得来终觉浅&#xff0c;绝知此事要躬行。大家好&#xff01;我是霜淮子&#xff0c;欢迎订阅我的专栏《算法系列》。 学习经典算法和经典代码&#xff0c;建立算法思维&#xff1b;大量编码让代码成为我们大脑的一部分。 ⭐️已更系列 1、基础数据结构 1.1、链表➡传送门 1…...

电路设计的一些概念

锁存器的产生 论述1 (转)时序电路&#xff0c;生成触发器&#xff0c;触发器是有使能端的&#xff0c;使能端无效时数据不变&#xff0c;这是触发器的特性。 组合逻辑&#xff0c;由于数据要保持不变&#xff0c;只能通过锁存器来保存。 第一个代码&#xff0c;由于是时序逻…...

【Linux】Linux下权限的理解

前言&#xff1a;在之前我们已经对基本的指令进行了深入的学习&#xff0c;接下来我将带领大家学习的是关于权限的相关问题。在之前&#xff0c;我们一直是使用的【root】用户&#xff0c;即为“超级用户”&#xff0c;通过对权限的学习之后&#xff0c;我们就会慢慢的切换到普…...

Prometheus监控实战系列十七:探针监控

目前对于应用程序的监控主要有两种方式&#xff0c;一种被称为白盒监控&#xff0c;它通过获取目标的内部信息指标&#xff0c;来监控目标的状态情况&#xff0c;我们前面介绍的主机监控、容器监控都属于此类监控。另一种则是“黑盒监控”&#xff0c;它指在程序外部通过探针的…...

题目:JPA的懒加载失效是什么情况?

题目&#xff1a;JPA的懒加载失效是什么情况&#xff1f;Q1&#xff1a;什么是JPA的懒加载&#xff1f;Q2&#xff1a;JPA的懒加载会在什么情况下失效&#xff1f;Q3&#xff1a;如何避免JPA的懒加载失效&#xff1f;前言&#xff1a;在使用JPA进行数据库操作时&#xff0c;懒加…...

十六、消息推送

一、什么是消息推送&#xff1f; 消息推送通常是指网站的运营工作等人员&#xff0c;通过某种工具对用户当前网页或移动设备 APP 进行的主动消息推送。 消息推送一般又分为 Web 端消息推送和移动端消息推送。 消息推送无非是推&#xff08;push&#xff09;和拉&#xff08;p…...

PMP项目管理-【第一章】引论

项目知识体系&#xff1a; 项目管理知识体系&#xff1a; 1.1 项目特性 独特性&#xff1a;独特性会带来不确定性(风险) 临时性&#xff1a;1> 任何项目都有起始终止时间 2> 项目具备临时性&#xff0c;项目成果可能是永久的 1.2 项目驱动变革 从商业角度来看&#xff0c…...

前端布局小案例,分享3个漂亮的卡片组件

当今互联网发展迅猛&#xff0c;各种应用、网站和软件层出不穷&#xff0c;其中前端技术的发展更是让人瞩目。随着用户对于界面设计的要求越来越高&#xff0c;漂亮的卡片组件在各类网页设计中变得越来越流行。本文将分享三个精美的卡片组件&#xff0c;帮助您在前端开发中轻松…...

博客重载记录

博客重载记录流控算法实现open系统调用流程二分查找前言&#xff1a; 有时候看了一些比较好的文章&#xff0c;过几天就忘了&#xff0c;想想不如自己实现一遍博客代码或按博客结构自己写一遍&#xff0c;加深印象&#xff0c;但把别人的内容改个名字变成自己的博客&#xff0c…...

open-cv绘制简单形状line() circle() rectangle() polylines() putText() cvtColor()

OpenCV彩色图像中一个像素是按照“B-G-R”模式组织的。 绘图函数的一些公众参数&#xff1a; img &#xff1a;图像对象 color&#xff1a; 颜色&#xff0c;如果彩色用一个三元组表示&#xff0c;三元组的元素按照B-G-R组织&#xff0c;三元组(0,255,0)中B为0&#xff0c;G为2…...

基于 PyTorch + LSTM 进行时间序列预测(附完整源码)

时间序列数据&#xff0c;顾名思义是一种随时间变化的数据类型。 例如&#xff0c;24小时内的温度、一个月内各种产品的价格、某家公司一年内的股票价格等。深度学习模型如长短期记忆网络&#xff08;LSTM&#xff09;能够捕捉时间序列数据中的模式&#xff0c;因此可以用于预…...

GEE页面介绍

目录一、背景二、用户界面三、数据类型&#xff1a;栅格1、请求图像集合2、学习查看栅格元数据3、矢量实例一&#xff1a;四、数据集五、数据属性1、空间分辨率2、时间分辨率六可视化多个波段1、真彩色(TCI)2彩色红外&#xff08;CI&#xff09;3、伪色 1 和 2 (FC1/FC2)七、可…...

python自动发送邮件,qq邮箱、网易邮箱自动发送和回复

在python中&#xff0c;我们可以用程序来实现向别人的邮箱自动发送一封邮件&#xff0c;甚至可以定时&#xff0c;如每天8点钟准时给某人发送一封邮件。今天&#xff0c;我们就来学习一下&#xff0c;如何向qq邮箱&#xff0c;网易邮箱等发送邮件。 一、获取邮箱的SMTP授权码。…...

hastcat

hashcat 下载地址: https://hashcat.net/hashcat/ 案例 Usage: hashcat [options]... hash|hashfile|hccapxfile [dictionary|mask|directory]...https://xz.aliyun.com/t/4008破解linux shadow /etc/shadow中密码格式: $id$salt$encrypted如:$1$2eWq10AC$NaQqalCk3 1表…...

242. 一个简单的整数问题

Powered by:NEFU AB-IN Link 文章目录242. 一个简单的整数问题题意思路代码242. 一个简单的整数问题 题意 给定长度为 N的数列 A&#xff0c;然后输入 M行操作指令。 第一类指令形如 C l r d&#xff0c;表示把数列中第 l∼r个数都加 d 第二类指令形如 Q x&#xff0c;表示询问…...

docker安装Redis高可用(一主二从三哨兵)

本次教程使用docker swarm安装 准备三台机器 hostIP用途node1192.168.31.130redis-master01&#xff0c;redis哨兵节点01node2192.168.31.131redis-slave01, redis哨兵节点02node3192.168.31.132redis-slave02 redis哨兵节点02 注意事项&#xff1a; 1&#xff1a;需要保证三…...

网站死链接怎么删除/搜狗站长工具

从Unity 2018.3&#xff08;TextMeshPro1.4&#xff09;起&#xff0c;添加了Font Fallback和Dynamic SDF System以实现灵活的SDF使用。有了这个新功能后&#xff0c;我们可以实现以下用法&#xff1a;预先为中文字中经常使用的字符生成普通SDF根据需要追加取得使用频率低的文字…...

做网站公司商丘/网络营销策划方案书范文

日前&#xff0c;网安专业媒体安全牛【牛人访谈】栏目专访了知道创宇CSO黑哥&#xff08;周景平&#xff09;。 围绕知道创宇出版的新书《网络空间测绘技术与实践》&#xff0c;安全牛分析师与黑哥就网络空间测绘技术当下的应用与挑战、未来的发展与创新进行了对话与交流。 以…...

.net最新网站开发/无锡营销型网站建设

前言 是不是有很多小伙伴在做接口自动化的时候&#xff0c;大量的测试用例数据&#xff0c;写的即枯燥&#xff0c;有乏味呢&#xff1f; 那么下面你们的福利来啦~本文章会基于 mitmproxy python 做代理拦截&#xff0c;将我们拦截到的接口请求&#xff0c;转换成 .yaml 格式…...

做网站利润/优秀网页设计公司

前言微软今年推出了新版的 Microsoft Edge 浏览器&#xff0c;与原本 Win10 内置的 UWP 版完全不同。新版 Edge 和 Chrome 一样基于开源项目 Chromium&#xff0c;性能上应该是没问题的。虽然还没有发布正式版&#xff0c;但稳定测试版 Beta Channel 已经可以下载了。这几天我安…...

深圳有没有可以做家教的网站/百度推广登录网站

“IBI Hack”是一项为期一个月的黑客马拉松&#xff0c;将于7月1日开始&#xff0c;由伊利诺伊州区块链技术协议组织以及区块链技术初创公司Fulcrum举办。区块链马拉松向全球的学生和大学毕业生开放。所有参赛作品截止于7月31日。 “IBI Hack”是伊利诺伊州区块链倡议活动的一部…...

做第一个php网站/热狗seo顾问

周次 学习时间 新编写代码行数 博客量&#xff08;篇&#xff09; 学到知识点 本周 5 80(HTML的不知道算不算) 1 JAVA基础&#xff0c;网络基础的静态路由配置&#xff0c; XX XXX XXXX XXXX 转载于:https://www…...