数据结构C语言描述3(图文结合)--双链表、循环链表、约瑟夫环问题

前言

  • 这个专栏将会用纯C实现常用的数据结构和简单的算法;
  • 有C基础即可跟着学习,代码均可运行;
  • 准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言实现的原因之一;
  • 欢迎收藏 + 关注,本人将会持续更新。

文章目录

  • 双向链表
    • 简介
    • 双链表实现
  • 循环链表
  • 循环链表约瑟夫环问题

双向链表

简介

🚡 双向链表,对比单链表来说,顾名思义,就是指向指向有两个指针,指向前后节点

🌾 结合单链表,单链表有无头和有头之分,双向链表也是一样,这里是无头双链表,采用再封装写法,不是二级指针写法再封装写法比较写起来比较容易,个人比较偏爱🤠🤠🤠🤠

双链表图示:

在这里插入图片描述

🉑 从ADT抽象中来说:

总结起来一句话:增删改查,🤠🤠🤠,假设双向链表是一个结合,这这个结合功能有:

  • 增加元素
  • 删除元素
  • 拿取元素
  • 查询元素
  • 修改元素
  • …………………………

双链表实现

这里采用再封装的方法,实现无头链表,有头和无头再单链表的那一节以及讲过了,这里采用无头实现

💠 节点封装

在双链表中,对于每一个节点来说,都有一个指向前、指向后节点的指针。

typedef int DataType;

typedef struct Node {
	DataType data;
	struct Node* prev;  // 前
	struct Node* next;   // 后
}Node;

⚜️ 链表封装

这一步封装的作用是,可以更好的操作链表的一些操作,这个size的一个再封装写法的核心,无头与有头再实现的过程中,核心就在于第一个头节点的处理,无头如果没有任何节点,则插入的节点则作为第一个节点,但是这样会改变指针的指向,这也是因为需要传递二级指针的原因,而再封装写法则很好的解决了这个问题。

typedef struct List {
	Node* headNode;
	Node* tailNode;
	int size;
}List;

🍨 创建节点

采用calloc创建节点,这样可以自动赋值为0

Node* create_node(DataType data)
{
	Node* node = (Node*)calloc(1, sizeof(Node));
	assert(node);
	node->data = data;
	return node;
}

🍤 创建链表

List* create_list()
{
	List* list = (List*)calloc(1, sizeof(List));
	assert(list);
	return list;
}

🤕 插入–头插

  • 情况判断:是否为空链表
    • 空链表:插件节点,作为头
    • 不为空:头插,如图:
void push_front(List* list, DataType data)
{
	if (list == NULL) {
		return;
	}
	Node* node = create_node(data);
	if (list->size == 0) {    // 这种写法的优势,不用传递二级指针
		list->tailNode = node;
	}
	else {
		node->next = list->headNode;
		list->headNode->prev = node;
	}
	list->headNode = node;
	list->size++;
}

🌮 插入–尾插入

  • 情况判断:是否为空链表
    • 为空:插入,作为头
    • 不为空:找到尾节点,插入
void push_back(List* list, DataType data)
{
	if (list == NULL) {
		return;
	}

	Node* node = create_node(data);

	if (list->size == 0) {
		list->headNode = node;
	}
	else {
		list->tailNode->next = node;
		node->prev = list->tailNode;
	}
	list->tailNode = node;
	list->size++;
}

💠 插入–任意位置

  • 规则: 在元素后位置插入
  • 情况:3种
    • 没有该元素
    • 尾插
    • 任意插
void insert(List* list, DataType posData, DataType data)
{
	if (list == NULL || list->size == 0) {  // size != 0 保证有头
		return;
	}

	Node* t = list->headNode;

	while (t->next != NULL && t->data != posData) {
		t = t->next;
	}

	if (t->data != posData) {   // 没有该元素
		return;
	}
	else if (t->next == NULL && t->data == posData) {  // 尾插
		Node* node = create_node(data);
		node->prev = t;
		t->next = node;
		list->tailNode = node;   // 尾巴移位
	}
	else{
		Node* node = create_node(data);
		node->next = t->next;
		t->next->prev = node;
		node->prev = t;
		t->next = node;
	}
	list->size++;
}

🎧 删除–头删

注意点:释放后指针指向问题:

  • 如果说就一个元素,则删除后,在封装头需要指向NULL
  • 如果不是,则下一个元素的prev指针需要赋值为NULL
void pop_front(List* list)
{
	if (list == NULL || list->size == 0) {
		return;
	}

	Node* node = list->headNode;
	list->headNode = node->next;
	free(node);
	(list->headNode) ? (list->headNode->prev = NULL) : (list->tailNode = NULL); // 判断是否只有一个节点的情况
	node = NULL;
}

🚖 删除–尾删除

注意点:释放后指针指向问题:

  • 如果说就一个元素,则删除后,在封装头需要指向NULL
  • 如果不是,则上一个元素的next指针需要赋值为NULL
void pop_back(List* list)
{
	if (list == NULL || list->size == 0) {
		return;
	}

	Node* node = list->tailNode;
	list->tailNode = list->tailNode->prev;
	free(node);
	(list->tailNode) ? (list->tailNode->next = NULL) : (list->headNode = NULL);
	list->size--;
}

🦅 删除–任意位置删除

四种情况:

  • 没有找到
  • 找到了
    • 头删
    • 尾删
    • 任意位置删
void erase(List* list, DataType posData)
{
	if (list == NULL || list->size == 0) {
		return;
	}

	Node* cur = list->headNode;

	while (cur->next != NULL && cur->data != posData) {
		cur = cur->next;
	}

	// 没有找到
	if (cur->data != posData) {
		return;
	}
	else if (cur->next == NULL) {   // 尾删除
		pop_back(list);
	}
	else if (cur->prev == NULL) {   // 头删
		pop_front(list);
	}
	else {
		Node* t = cur;
		cur->prev->next = cur->next;
		cur->next->prev = cur->prev;
		free(t);
		t = NULL;
		list->size--;
	}
}


🌐 万金油函数

bool empty(List* list)
{
	if (list == NULL) {
		return true;
	}

	return list->size == 0;
}

size_t size(List* list)
{
	if (list == NULL) {
		return 0;
	}
	return list->size;
}


📤 向前遍历

void travel_front(List* list)
{
	if (list == NULL) {
		return;
	}

	Node* cur = list->headNode;
	while (cur) {
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

🎉 向后遍历

void travel_back(List* list)
{
	if (list == NULL) {
		return;
	}

	Node* cur = list->tailNode;
	while (cur) {
		printf("%d ", cur->data);
		cur = cur->prev;
	}
	printf("\n");
}

总代码

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

typedef int DataType;

typedef struct Node {
	DataType data;
	struct Node* prev;
	struct Node* next;
}Node;

typedef struct List {
	Node* headNode;
	Node* tailNode;
	int size;
}List;

Node* create_node(DataType data)
{
	Node* node = (Node*)calloc(1, sizeof(Node));
	assert(node);
	node->data = data;
	return node;
}

List* create_list()
{
	List* list = (List*)calloc(1, sizeof(List));
	assert(list);
	return list;
}

void push_front(List* list, DataType data)
{
	if (list == NULL) {
		return;
	}
	Node* node = create_node(data);
	if (list->size == 0) {
		list->tailNode = node;
	}
	else {
		node->next = list->headNode;
		list->headNode->prev = node;
	}
	list->headNode = node;
	list->size++;
}

void push_back(List* list, DataType data)
{
	if (list == NULL) {
		return;
	}

	Node* node = create_node(data);

	if (list->size == 0) {
		list->headNode = node;
	}
	else {
		list->tailNode->next = node;
		node->prev = list->tailNode;
	}
	list->tailNode = node;
	list->size++;
}

void insert(List* list, DataType posData, DataType data)
{
	if (list == NULL || list->size == 0) {  // size != 0 保证有头
		return;
	}

	Node* t = list->headNode;

	while (t->next != NULL && t->data != posData) {
		t = t->next;
	}

	if (t->data != posData) {   // 没有该元素
		return;
	}
	else if (t->next == NULL && t->data == posData) {  // 尾插
		Node* node = create_node(data);
		node->prev = t;
		t->next = node;
		list->tailNode = node;   // 尾巴移位
	}
	else{
		Node* node = create_node(data);
		node->next = t->next;
		t->next->prev = node;
		node->prev = t;
		t->next = node;
	}
	list->size++;
}

void pop_front(List* list)
{
	if (list == NULL || list->size == 0) {
		return;
	}

	Node* node = list->headNode;
	list->headNode = node->next;
	free(node);
	(list->headNode) ? (list->headNode->prev = NULL) : (list->tailNode = NULL); // 判断是否只有一个节点的情况
	node = NULL;
}

void pop_back(List* list)
{
	if (list == NULL || list->size == 0) {
		return;
	}

	Node* node = list->tailNode;
	list->tailNode = list->tailNode->prev;
	free(node);
	(list->tailNode) ? (list->tailNode->next = NULL) : (list->headNode = NULL);
	list->size--;
}

void erase(List* list, DataType posData)
{
	if (list == NULL || list->size == 0) {
		return;
	}

	Node* cur = list->headNode;

	while (cur->next != NULL && cur->data != posData) {
		cur = cur->next;
	}

	// 没有找到
	if (cur->data != posData) {
		return;
	}
	else if (cur->next == NULL) {   // 尾删除
		pop_back(list);
	}
	else if (cur->prev == NULL) {   // 头删
		pop_front(list);
	}
	else {
		Node* t = cur;
		cur->prev->next = cur->next;
		cur->next->prev = cur->prev;
		free(t);
		t = NULL;
		list->size--;
	}
}

bool empty(List* list)
{
	if (list == NULL) {
		return true;
	}

	return list->size == 0;
}

size_t size(List* list)
{
	if (list == NULL) {
		return 0;
	}
	return list->size;
}

void travel_front(List* list)
{
	if (list == NULL) {
		return;
	}

	Node* cur = list->headNode;
	while (cur) {
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

void travel_back(List* list)
{
	if (list == NULL) {
		return;
	}

	Node* cur = list->tailNode;
	while (cur) {
		printf("%d ", cur->data);
		cur = cur->prev;
	}
	printf("\n");
}

int main()
{
	List* list = create_list();
	for (int i = 1; i < 4; i++) {
		push_front(list, i);
	}
	for (int i = 1; i < 4; i++) {
		push_back(list, i * 10);
	}
	travel_front(list);
	travel_back(list);

	insert(list, 3, 33);
	insert(list, 30, 300);
	travel_front(list);
	travel_back(list);

	pop_front(list);
	travel_front(list);
	travel_back(list);

	pop_back(list);
	travel_front(list);
	travel_back(list);

	erase(list, 33);
	erase(list, 30);
	erase(list, 10);
	travel_front(list);
	travel_back(list);

	return 0;
}

循环链表

循环链表分为循环单链表,循环双链表,单链表和双链表又分为有头和无头链表,这里是有头循环双链表

双向循环链表(Doubly Circular Linked List)是一种数据结构,其中每个节点都包含两个指针,一个指向前一个节点,一个指向后一个节点。与普通链表不同的是,双向循环链表的最后一个节点的下一个指针指向头节点,而头节点的前一个指针指向最后一个节点,形成一个循环。

在这里插入图片描述


🤕 节点封装

typedef int DataType;

typedef struct Node {
	DataType data;
	struct Node* prev;
	struct Node* next;
}Node;

🍨 创建节点

Node* create_node(DataType data) 
{
	Node* node = (Node*)calloc(1, sizeof(Node));
	assert(node);
	node->data = data;
	return node;
}

⚜️ 创建链表

这里需要构建一个循环节点(链表),如图:

在这里插入图片描述

Node* create_list()
{
	Node* list = (Node*)calloc(1, sizeof(Node));
	assert(list);
	list->next = list;
	list->prev = list;
	return list;
}

🎧 插入–头插

双向头删就很容易了,如图:

在这里插入图片描述

void push_front(Node* list, DataType data)
{
	assert(list);

	Node* node = create_node(data);
	node->next = list->next;
	list->next->prev = node;   // 难点,不用担心 next,prev为空的时候
	node->prev = list;
	list->next = node;
}

🌮 插入–尾插

尾巴删除也很容易,因为头和尾巴互相找到,如图:

在这里插入图片描述

void push_back(Node* list, DataType data)
{
	assert(list);

	Node* node = create_node(data);
	node->prev = list->prev;
	list->prev->next = node;
	node->next = list;
	list->prev = node;
}

⛹️‍♀️ 插入–任意位置

任意位置也不难,找到要插入的位置,要注意的是找不到的情况

// 找到要插入那个节点的位置节点
void insert(Node* list, DataType posData ,DataType data)
{
	assert(list);

	Node* cur = list->next;

	while (cur->next != list && cur->data != posData) {
		cur = cur->next;
	}

	if (cur->data != posData) {   // 思考,为什么不能 cur->next != list ?????
		return;
	}
	else {
		Node* node = create_node(data);
		node->next = cur->next;
		cur->next->prev = node;
		node->prev = cur;
		cur->next = node;
	}

}

👟 删除–头删

注意: 一个节点的头节点指向不同。

两种情况:

  1. 如果一个元素,这个时候删除,头节点指向修改和两个元素以上删除不同,这个时候头节点需要指向自己
  2. 两个元素及上
void pop_front(Node* list)
{
	assert(list);

	Node* cur = list->next;

	if (cur == list) {   // 无节点
		return;
	}
	else if(cur->next == list) {   // 一个节点
		list->prev = list;
		list->next = list;
	}
	else {
		list->next = cur->next;   // 两个节点以上
		cur->next->prev = list;
	}
	free(cur);
	cur = NULL;
}

📑 删除–尾删

这个也是简单的,因为可以通过头节点直接找到尾节点,这个时候就只需要一种情况即可,因为创建双链表有一个很好的特性,

void pop_back(Node* list)
{
	assert(list);

	Node* cur = list->prev;   // 因为可以获取尾节点

	if (cur == list) {
		return;
	}
	else {
		cur->prev->next = list;   // 哪怕是一个节点,也和普通情况也是一样
		list->prev = cur->prev;   // 这个也是一样,
		free(cur);
		cur = NULL;
	}

}

🚴‍♀ 删除–任意位置

很简单,因为这个也不用记录前驱节点,也不用找尾节点了,只需要考虑两种情况:

  1. 没有找到
  2. 找到了
void erase(Node* list, DataType posData)
{
	assert(list);

	Node* cur = list->next;

	while (cur->next != list && cur->data != posData) {
		cur = cur->next;
	}

	if (cur->data != posData) {
		return;
	}
	else {
		cur->prev->next = cur->next;
		cur->next->prev = cur->prev;
		free(cur);
		cur = NULL;
	}
}

🔱 遍历

void travel_front(Node* list)
{
	assert(list);

	Node* cur = list->next;
	while (cur != list) {
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

void travel_back(Node* list)
{
	assert(list);

	Node* cur = list->prev;

	while (cur != list) {
		printf("%d ", cur->data);
		cur = cur->prev;
	}
	printf("\n");
}

⚗️ 总代码

#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>

// 有头链表实现,简单点

typedef int DataType;

typedef struct Node {
	DataType data;
	struct Node* prev;
	struct Node* next;
}Node;


Node* create_node(DataType data) 
{
	Node* node = (Node*)calloc(1, sizeof(Node));
	assert(node);
	node->data = data;
	return node;
}

Node* create_list()
{
	Node* list = (Node*)calloc(1, sizeof(Node));
	assert(list);
	list->next = list;
	list->prev = list;
	return list;
}

void push_front(Node* list, DataType data)
{
	assert(list);

	Node* node = create_node(data);
	node->next = list->next;
	list->next->prev = node;   // 难点,不用担心 next,prev为空的时候
	node->prev = list;
	list->next = node;
}

void push_back(Node* list, DataType data)
{
	assert(list);

	Node* node = create_node(data);
	node->prev = list->prev;
	list->prev->next = node;
	node->next = list;
	list->prev = node;
}
// 找到要插入那个节点的位置节点
void insert(Node* list, DataType posData ,DataType data)
{
	assert(list);

	Node* cur = list->next;

	while (cur->next != list && cur->data != posData) {
		cur = cur->next;
	}

	if (cur->data != posData) {   // 思考,为什么不能 cur->next != list ?????
		return;
	}
	else {
		Node* node = create_node(data);
		node->next = cur->next;
		cur->next->prev = node;
		node->prev = cur;
		cur->next = node;
	}

}

void pop_front(Node* list)
{
	assert(list);

	Node* cur = list->next;

	if (cur == list) {
		return;
	}
	else if(cur->next == list) {
		list->prev = list;
		list->next = list;
	}
	else {
		list->next = cur->next;
		cur->next->prev = list;
	}
	free(cur);
	cur = NULL;
}

void pop_back(Node* list)
{
	assert(list);

	Node* cur = list->prev;

	if (cur == list) {
		return;
	}
	else {
		cur->prev->next = list;
		list->prev = cur->prev;
		free(cur);
		cur = NULL;
	}

}

void erase(Node* list, DataType posData)
{
	assert(list);

	Node* cur = list->next;

	while (cur->next != list && cur->data != posData) {
		cur = cur->next;
	}

	if (cur->data != posData) {
		return;
	}
	else {
		cur->prev->next = cur->next;
		cur->next->prev = cur->prev;
		free(cur);
		cur = NULL;
	}
}

void travel_front(Node* list)
{
	assert(list);

	Node* cur = list->next;
	while (cur != list) {
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

void travel_back(Node* list)
{
	assert(list);

	Node* cur = list->prev;

	while (cur != list) {
		printf("%d ", cur->data);
		cur = cur->prev;
	}
	printf("\n");
}

int main()
{
	Node* list = create_list();

	push_front(list, 1);
	push_front(list, 2);
	push_front(list, 3);
	travel_front(list);
	travel_back(list);

	push_back(list, 11);
	push_back(list, 22);
	push_back(list, 33);
	travel_front(list);
	travel_back(list);

	insert(list, 2, 20);
	insert(list, 3, 30);
	insert(list, 33, 330);
	travel_front(list);
	travel_back(list);

	pop_front(list);
	travel_front(list);
	travel_back(list);

	pop_back(list);
	travel_front(list);
	travel_back(list);

	erase(list, 33);
	travel_front(list);
	travel_back(list);

	return 0;
}

循环链表约瑟夫环问题

讲一个比较有意思的故事:约瑟夫是犹太军队的一个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队40余人,他们都是宁死不屈的人,所以不愿投降做叛徒。一群人表决说要死,所以用一种策略来先后kill所有人。
于是约瑟夫建议:每次由其他两人一起kill一个人,而被kill的人的先后顺序是由抽签决定的,约瑟夫有预谋地抽到了最后一签,在kill了除了他和剩余那个人之外的最后一人,他劝服了另外一个没死的人投降了罗马。

我们这个规则是这么定的

  • 在一间房间总共有n个人(下标0~n-1),只能有最后一个人活命。
  • 按照如下规则去排除人:
    • 所有人围成一圈
    • 顺时针报数,每次报到q的人将被排除掉
    • 被排除掉的人将从房间内被移走
    • 然后从被kill掉的下一个人重新报数,继续报q,再清除,直到剩余一人
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

/*
* 用上一个链表,也可以。这里采用无头循环双链表实现
* 无头采用再次封装的写法
*/

typedef struct Node {
	int data;
	struct Node* prev;
	struct Node* next;
}Node;

typedef struct List {
	Node* headNode;
}List;

// 每一个节点创建都是循环
Node* create_node(int data)
{
	Node* node = (Node*)calloc(1, sizeof(Node));
	assert(node);
	node->data = data;
	node->prev = node;
	node->next = node;
	return node;
}

void push_back(List* list, int data)
{
	assert(list);

	Node* node = create_node(data);

	if (list->headNode == NULL) {
		list->headNode = node;
	}
	else {
		Node* cur = list->headNode->prev;

		node->next = list->headNode;
		list->headNode->prev = node;
		cur->next = node;
		node->prev = cur;
	}
}

void erase(List* list, Node* node)
{
	assert(list);
	assert(node);

	// 一个节点
	if (node->next == node) {
		free(node);
		node = NULL;
		list->headNode = NULL;
	}
	else {
		node->prev->next = node->next;
		node->next->prev = node->prev;
		if (list->headNode == node) {   // 防止删除头
			list->headNode = node->next;
		}
		free(node);
		node = NULL;
	}
}

void travel(List* list)
{
	Node* cur = list->headNode;

	while (cur->next != list->headNode) {
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("%d ", cur->data);
	printf("\n");
}

// 只做演示,不考虑内存问题
void game_run(int n, int m)
{
	if (n < 0 || m < 0) {
		return;
	}

	List list = { NULL };

	for (int i = 1; i <= n; i++) {
		push_back(&list, i);
	}

	travel(&list);

	Node* cur = list.headNode;

	while (n > 1) {
		// 报数
		for (int i = 1; i < m; i++) {
			cur = cur->next;
		}
		Node* next = cur->next;
		erase(&list, cur);
		// 重置报数
		cur = next;
		n--;
	}

	printf("天选之子: %d\n", cur->data);
}


int main()
{
	game_run(10, 3);

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/919957.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入理解Flutter生命周期函数之StatefulWidget(一)

目录 前言 1.为什么需要生命周期函数 2.开发过程中常用的生命周期函数 1.initState() 2.didChangeDependencies() 3.build() 4.didUpdateWidget() 5.setState() 6.deactivate() 7.dispose() 3.Flutter生命周期总结 1.调用顺序 2.函数调用时机以及主要作用 4.生…

uniapp vue3小程序报错Cannot read property ‘__route__‘ of undefined

在App.vue里有监听应用的生命周期 <script>// 只能在App.vue里监听应用的生命周期export default {onError: function(err) {console.log(AppOnError:, err); // 当 uni-app 报错时触发}} </script>在控制台打印里无意发现 Cannot read property ‘__route__‘ of …

ESP32移植Openharmony外设篇(5)aht20温湿度传感器

模块简介 产品概述 AHT20&#xff0c;新一代温湿度传感器在尺寸与智能方面建立了新的标准&#xff1a;它嵌入了适于回流焊的双列扁平无引脚SMD封装&#xff0c;底面 3 x 3mm &#xff0c;高度1.0mm。传感器输出经过标定的数字信号&#xff0c;标准 I2 C 格式。 AHT20 配有一个…

量子计算来袭:如何保护未来的数字世界

目录 前言 一、量子计算安全的学习方向 1. 量子物理学基础 2. 量子计算原理与技术 3. 传统网络安全知识 4. 量子密码学 5. 量子计算安全政策与法规 二、量子计算的漏洞风险 1. 加密算法被破解风险 2. 区块链安全风险 3. 量子密钥分发风险 4. 量子计算系统自身风险 …

Git入门图文教程 -- 深入浅出 ( 保姆级 )

01、认识一下Git&#xff01;—简介 Git是当前最先进、最主流的分布式版本控制系统&#xff0c;免费、开源&#xff01;核心能力就是版本控制。再具体一点&#xff0c;就是面向代码文件的版本控制&#xff0c;代码的任何修改历史都会被记录管理起来&#xff0c;意味着可以恢复…

C++之异常

1.异常的概念及其使用 1.1 异常的概念 异常是一种用于处理错误的机制&#xff0c;它允许程序在检查到错误条件时&#xff0c;能够从一个代码块转到另一个代码块&#xff0c;以处理改错误&#xff0c;而不是直接崩溃返回不确定的结果。 C的异常处理机制依赖于三个关键字&#x…

Golang语言整合jwt+gin框架实现token

1.下载jwt go get -u github.com/dgrijalva/jwt-go2.新建生成token和解析token文件 2.1 新建common文件夹和jwtConfig文件夹 新建jwtconfig.go文件 2.2 jwtconfig.go文件代码 /* Time : 2021/8/2 下午3:03 Author : mrxuexi File : main Software: GoLand */ package jwtC…

河工oj(1101-1113)

1101 求组合数&#xff08;函数专题&#xff09; 代码 #include<bits/stdc.h> using namespace std;int fact(int n) {int res 1;while(n) {res * n--;}return res; } int main() {int m, k;cin >> m >> k;cout << fact(m)/fact(k)/fact(m-k) <&l…

07架构面试题

目录 一、关于合生元的面试题的架构分析的问题 1. 陈述两种方案的优劣 2. 在那些条件下&#xff0c;会选择哪一个方案 3. 你倾向那一种&#xff1f; 4. 如果要实施方案二的&#xff0c;准备步骤和流程 一、关于合生元的面试题的架构分析的问题 1. 陈述两种方案的优劣 方案…

递归:编程世界的奇妙魔法之旅

模块一&#xff1a;递归的神秘面纱 —— 初窥魔法之门 1. 递归的概念&#xff1a;神秘的魔法回响 &#x1f60e;嘿&#xff01;各位编程大侠们&#xff0c;今天咱们要来聊聊一个超级神奇的玩意儿 —— 递归。这递归啊&#xff0c;简直就是编程世界里神秘得不能再神秘的魔法回…

力扣题目总结

1.游戏玩法分析IV AC: select IFNULL(round(count(distinct(Result.player_id)) / count(distinct(Activity.player_id)), 2), 0) as fraction from (select Activity.player_id as player_idfrom (select player_id, DATE_ADD(MIN(event_date), INTERVAL 1 DAY) as second_da…

Ubuntu22.04LTS 部署前后端分离项目

一、安装mysql8.0 1. 安装mysql8.0 # 更新安装包管理工具 sudo apt-get update # 安装 mysql数据库&#xff0c;过程中的选项选择 y sudo apt-get install mysql-server # 启动mysql命令如下 &#xff08;停止mysql的命令为&#xff1a;sudo service mysql stop&#xff0…

(Linux)搭建静态网站——基于http/https协议的静态网站

简单了解nginx配置文件 1.下载并开启nginx服务 下载 [rootlocalhost ~]# dnf install nginx -y开启 [rootlocalhost ~]# systemctl restart nginx 1.(1)搭建静态网站——基于http协议的静态网站 实验1&#xff1a;搭建一个web服务器&#xff0c;访问该服务器时显示“hello w…

vue3:scss引用

原文查看&#xff1a;https://mp.weixin.qq.com/s?__bizMzg3NTAzMzAxNA&mid2247484356&idx2&sn44b127cd394e217b9e3c4eccafdc0aa9&chksmcec6fb1df9b1720b7bd0ca0b321bf8a995fc8cba233deb703512560cbe451cfb1f05cdf129f6&token1776233257&langzh_CN#rd…

Oracle - 多区间按权重取值逻辑 ,分时区-多层级-取配置方案(二)

Oracle - 多区间按权重取值逻辑 &#xff0c;分时区-多层级-取配置方案https://blog.csdn.net/shijianduan1/article/details/133386281 某业务配置表&#xff0c;按配置的时间区间及组织层级取方案&#xff0c;形成报表展示出所有部门方案的取值&#xff1b; 例如&#xff0…

13.C++内存管理2(C++ new和delete的使用和原理详解,内存泄漏问题)

⭐本篇重点&#xff1a;new, delete的使用和原理 ⭐本篇代码&#xff1a;c学习/04.c-动态内存管理 橘子真甜/c-learning-of-yzc - 码云 - 开源中国 (gitee.com) 目录 一. new和delete的使用 1.1 操作内置类型 1.2 操作自定义类型 二. new, delete与malloc, free的区别 2.1…

用源码编译虚幻引擎,并打包到安卓平台

用源码编译虚幻引擎&#xff0c;并打包到安卓平台 前往我的博客,获取更优的阅读体验 作业内容: 源码编译UE5.4构建C项目&#xff0c;简单设置打包到安卓平台 编译虚幻 5 前置内容 这里需要将 Epic 账号和 Github 账号绑定&#xff0c;然后加入 Epic 邀请的组织&#xff0c…

golang通用后台管理系统09(系统操作日志记录)

1.日志工具类 package log/**** 日志记录 wangwei 2024-11-18 15:30*/ import ("log""os""path/filepath""time" )// 获取以当前日期命名的日志文件路径 func getLogFilePath() string {currentDate : time.Now().Format("2006-…

基于yolov8、yolov5的电塔缺陷检测识别系统(含UI界面、训练好的模型、Python代码、数据集)

摘要&#xff1a;电塔缺陷检测在电力设备巡检、运行维护和故障预防中起着至关重要的作用&#xff0c;不仅能帮助相关部门实时监测电塔运行状态&#xff0c;还为智能化检测系统提供了可靠的数据支撑。本文介绍了一款基于YOLOv8、YOLOv5等深度学习框架的电塔缺陷检测模型&#xf…

论文阅读 SeedEdit: Align Image Re-Generation to Image Editing

目录 摘要 1 INTRODUCTION 2 SEEDEDIT 2.1 T2I MODEL FOR EDITING DATA GENERATION 2.2 CAUSAL DIFFUSION MODEL WITH IMAGE INPUT 2.3 ITERATIVE ALIGNMENT 3 EXPERIMENTS 3.1 BENCHMARK AND METRICS 3.2 IMAGE EDITING COMPARISON 4 CONCLUSION 摘要 SeedEdit&…