交通指南系统

news2024/9/24 13:23:03

一、实验目的

1. 掌握图的基本存储方法;

2. 掌握有关图的操作算法并用高级语言实现;

3. 熟练掌握图的两种搜索路径的遍历方法。

二、实验内容

假设以一个带权有向图表示某一区域的公交线路网,图中顶点代表一些区域中的重要场所,弧代表已有的公交线路,弧上的权表示该线路上的票价(或搭乘所需时间),试设计一个交通指南系统,指导前来咨询者以最低的票价或最少的时间从区域中的某一场所到达另一场所。

三、实验步骤

1.用控制台输入和文件读入两种方式,把交通指南系统中的重要场所(定点)、公交线路(弧)、票价(弧上的权重)表示出来,存储在图中;

2.对图做初始化

3.深度优先DFS,标记已访问

4.贪心算法,更新最小票价

5.dijkstra算法,获取图中最短路径和最少票价

三、详细描述

(一) 数据结构设计

图论是数学的一个分支,图可以被表示为 G={V, E},其中 V={v1, ... , vN},E= {e1, ... , eM}。在本程序中,将顶点V用*vex描述,邻接矩阵用**arcs描述,顶点数和边数为vexNum,arcNum:

表 1 - 节点数据信息

数据项名称

数据项系统表示

数据类型

数据长度

备注

顶点

vexs

char*

邻接矩阵

arcs

int**

顶点数

vexNum

int

边数

arcNum

int

结构体函数如下:

(二)图的创建

1.图的初始化

定义Graph结构体,存放vexs(地点)、arcs(路径)、vexNum(地点数)、arcNum(路径数)。并编写initGraph函数,通过malloc函数动态分配空间。

初始化图,实质上就是给每个图中需要分配动态内存的地方都分配一个动态内存。

源码如下所示:

Graph* initGraph(int vexNum){

int i;

    Graph* G = (Graph*)malloc(sizeof(Graph));//给图G分配一个动态空间

    G->vexs = (char*)malloc(sizeof(char)*vexNum);//给顶点分配一个动态空间

    G->arcs = (int**)malloc(sizeof(int*)*vexNum);//给邻接矩阵分配一个动态空间

    for(i=0;i<vexNum;i++){

        G->arcs[i] = (int*)malloc(sizeof(int)*vexNum);//循环给邻接矩阵的第二层分配动态空间

    }

    G->vexNum = vexNum;//传值传值传值-传顶点数

    G->arcNum = 0;//给边数初始化为0

    return G;//好的!这里全部分配完空间了,所以可以打包送走了

}

2.图的创建

创建图,实质上就是把图中需要赋值的地方全部赋值一下,要注意的是,无向图的邻接矩阵是对称矩阵,源码如下:

void createGraph(Graph* G,char* vexs,int* arcs){

    int i,j;

for(i=0;i<G->vexNum;i++){

        G->vexs[i] = vexs[i];//先把顶点值传进去

        for(j=0;j<G->vexNum;j++){

            G->arcs[i][j] = *(arcs + i*G -> vexNum + j);//一维转二维了

            if(G->arcs[i][j] !=0 && G->arcs[i][j] != MAX)//数数有多少边

             G->arcNum ++;//边数++

        }

    }

    G->arcNum /= 2;//边数要除以2,因为矩阵有两半

}

3.图的释放

创建图的时候分配了一个内存空间,相应地,销毁图的时候就需要释放掉这些空间。

void freeGraph(Graph* G){

int i;

    for (i = 0; i < G->vexNum; i++)

    {

        free(G->vexs[i]);

        free(G->arcs[i]);

    }

    free(G->vexs);

    free(G->arcs);

    free(G);

}

(三)文件读取和控制台读取

文件读取使用了FILE *file = fopen(filename, "r+");打开文件,然后依次对文件内容进行遍历读入,存入Graph G中,流程图如图 1所示。

控制台的读取也是直接将用户输入的内容存放到Graph G中。流程和文件读入类似,在这不过多赘述了。

(四)菜单设计

为了设计好看、便捷的菜单,这里调用了一个库conio.h,这个库里有个函数getch(),读入到用户输入后,不需要换行即可进行下一句。设计的原则是“直到用户输入正确为止”,流程图如图 2所示。

 (五)迪杰斯特拉算法求最短路径和最少花费

迪杰斯特拉算法有三个关键元素,s记录了目标定点到其他顶点的最短路径是否求得,p记录了目标顶点到其他顶点的最短路径的前驱节点,d记录了目标顶点到其他顶点的最短路径的长度。首先对spd进行初始化,根据对应的顶点和路径赋初值。之后,首先通过getMin函数获取当前节点到其他所有节点中最短路径对应的节点,因为该路径已经是最短路径,如果在通过其他节点到达该路径那么一定会比当前路径长,所以获取到的最短路径就是对应的节点到初始节点的最短路径。之后根据将该最短路径作为中转,计算初始顶点和其他所有顶点的距离,在与我们初始化的距离作比较,如果相比较小,则记录在d数组中,之后再去获取最短路径,循环往复,直到获取完所有的最短路径。

测试阶段,使用excel工具模拟了一个邻接矩阵,如图 3所示。

使用画图工具,将上述邻接矩阵还原为图,如图 4所示。

 图 4 图的画图模拟

迪杰斯特拉算法的流程图表达,如图 5所示。

图 5 迪杰斯特拉算法流程图

根据上述方法,求解出了最短路径,输出案例为:

The shortest path is:1-->6-->5

The shortest path spend is: 18

完整运行结果如下一节所示。

五、运行结果

(一)测试文件输入公交线路网的功能

*************欢迎来到交通指南系统*************

-------------------菜单列表-------------------

*            1.文件输入公交线路网            *

*            2.控制台输入公交线路网          *

*            0.退出程序                      *

**********************************************

请选择:1

=====================

读入内容如下:

7 12

0 12 32767 32767 32767 16 14

12 0 10 32767 32767 7 32767

32767 10 0 3 5 6 32767

32767 32767 3 0 4 32767 32767

32767 32767 5 4 0 2 8

16 7 6 32767 2 0 9

14 32767 32767 32767 8 9 0

=====================

出发点:1

目的点:5

The shortest path is:1-->6-->5

The shortest path spend is: 18

-------按任意键回到主菜单--------

(二)测试控制台输入公交线路的功能

*************欢迎来到交通指南系统*************

-------------------菜单列表-------------------

*            1.文件输入公交线路网            *

*            2.控制台输入公交线路网          *

*            0.退出程序                      *

**********************************************

请选择:2

请输入重要地点数:

4

============================================

1地到2地是否有直达线路?(有填1,没有填0):

1

请输入票价:

40

0-->1  票价:40

============================================

1地到3地是否有直达线路?(有填1,没有填0):

1

请输入票价:

30

0-->2  票价:30

============================================

1地到4地是否有直达线路?(有填1,没有填0):

0

read success

============================================

2地到3地是否有直达线路?(有填1,没有填0):

1

请输入票价:

90

1-->2  票价:90

============================================

2地到4地是否有直达线路?(有填1,没有填0):

1

请输入票价:

20

1-->3  票价:20

============================================

3地到4地是否有直达线路?(有填1,没有填0):

0

read success

=====================

读入内容如下:

4 4

0 40 30 32767

40 0 90 20

30 90 0 32767

32767 20 32767 0

=====================

出发点:1

目的点:3

The shortest path is:1-->3

The shortest path spend is: 30

-------按任意键回到主菜单--------

(三)测试输入错误及退出

*************欢迎来到交通指南系统*************

-------------------菜单列表-------------------

*            1.文件输入公交线路网            *

*            2.控制台输入公交线路网          *

*            0.退出程序                      *

**********************************************

请选择:3

请选择:4

请选择:0

请按任意键继续. . .

六、心得与体会

这次的实验是图的最短路径的求解,共三种方法,弗洛伊德、迪杰斯特拉、Bellman-Ford算法。由于本程序是城市交通系统,不涉及权值为负的求解,因此,使用迪杰斯特拉算法就可以完成本题的求解。

实验一开始,肯定是要初始化、创建图,程序结束之后也得记得把申请的内存释放掉。相比以前,要用的时候就给这个地方申请内存的写法,我这次使用了统一在一个函数中申请内存,在一个函数中释放内存,比以前那种写法简直不要舒适太多。

本次实验的重点和难点是采用递归方式查询全部路径和采用迪杰斯特拉算法查询最短路径,递归方式查询全部路径的核心思想是递归查询当前节点的相邻节点,并将其确定为初始节点,递归判断初始节点与最终节点之间的路径。迪杰斯特拉算法查询最短路径的核心思想是每次获取当前节点相对其他所有节点的最短路径,在将其作为中继,生成新的路径,循环往复,最早找到当前节点相对于其他所有节点的最短路径。

在完成了代码的开发后,又开始了思考,能否对代码逻辑做一个优化,采用两种方式,一种是从文件读入,另一种是控制台输出,两种方法都做一个封装,提供给用户使用,带来更加舒适的使用体验。

这次的程序也存在缺点。比如释放图的那一步,我是最后才想起来做的,写程序的时候占了多少内存已经不知道了。还有就是对图的初始化,因为我得给每个点都放个名字,一开始设计结构体的时候没想起来,直接用了char*,然后一个一个裁了,导致地点名字只能是一个字符,如果当时用二维指针来做的话,这个问题就可以很好的解决了(可能在每个地点后面都补个,啥的也能解决)。其次,在设计createGraph这个函数的时候,把vexs直接传进去了,所以导致后面我如果想把接口提供给用户自己使用,又得写一个字符串的append函数,这些小瑕疵其实都可以在一开始设计结构体的时候就改为二维指针,直接规避掉。

最后,经过了此次实验,还是受益匪浅的,一个晚上一个奇迹,卡在ddl之前终于是结束了,舒了一口气,也可以开始课程设计的书写了。

七、源码

#include <stdio.h>
#include <stdlib.h>
#include <conio.h> 
#define MAX 32767

typedef struct Graph{
    char* vexs;//顶点 
    int** arcs;//邻接矩阵 
    int vexNum;//顶点数 
    int arcNum;//边数 
}Graph;

//初始化一个图 
//原理:全部分配动态空间 
Graph* initGraph(int vexNum){
	int i;
    Graph* G = (Graph*)malloc(sizeof(Graph));//给图G分配一个动态空间 
    G->vexs = (char*)malloc(sizeof(char)*vexNum);//给顶点分配一个动态空间 
    G->arcs = (int**)malloc(sizeof(int*)*vexNum);//给邻接矩阵分配一个动态空间 
    for(i=0;i<vexNum;i++){
        G->arcs[i] = (int*)malloc(sizeof(int)*vexNum);//循环给邻接矩阵的第二层分配动态空间 
    }
    G->vexNum = vexNum;//传值传值传值-传顶点数 
    G->arcNum = 0;//给边数初始化为0 
    return G;//好的!这里全部分配完空间了,所以可以打包送走了 
}
//释放内存 
void freeGraph(Graph* G){
	int i;
    for (i = 0; i < G->vexNum; i++)
    {
        free(G->vexs[i]);
        free(G->arcs[i]);
    }
    free(G->vexs);
    free(G->arcs);
    free(G);
}
//创建一个图 
//原理:循环,把顶点值和邻接矩阵都传进去,顺便把边数数出来 ,当然,是用顶点数组和边数组来传 
void createGraph(Graph* G,char* vexs,int* arcs){
    int i,j;
	for(i=0;i<G->vexNum;i++){
        G->vexs[i] = vexs[i];//先把顶点值传进去 
       
        for(j=0;j<G->vexNum;j++){
            G->arcs[i][j] = *(arcs + i*G -> vexNum + j);//一维转二维了 
            if(G->arcs[i][j] !=0 && G->arcs[i][j] != MAX)//数数有多少边 
            	G->arcNum ++;//边数++ 
        }
    }
    G->arcNum /= 2;//边数要除以2,因为矩阵有两半 
}


//深度优先遍历 
//原理:打印出这个点的值,标记为已访问, 
void DFS(Graph* G,int* visited,int index){
    int i;
    visited[index] = 1;//打印过就标记
    for(i=0;i<G->vexNum;i++){
        if(G->arcs[index][i] > 0 && G->arcs[index][i] != MAX && !visited[i])//如果这个点和别的点有联系,并且没访问过,就遍历! 
        DFS(G,visited,i);
    }
}

//获取最小值
//原理 :找到最小值,返回顶点序号 
int getMin(Graph* G,int* d,int* s){
    int i;
	int min = MAX;//先把值初始化为最大值 
    int index;
    for(i=0;i<G->vexNum;i++){
        if(!s[i] && d[i]<min){
            min = d[i];//最小值修改为最短路径 
            index = i;//最小的顶点序号给他丢进index里去 
        }
    }
    return index;
}

//迪杰斯特拉算法
//原理: 
void dijkstra(Graph *G, int end,int index){
	int i,j;
    int *s = (int *)malloc(sizeof(int) * G->vexNum);
    int *p = (int *)malloc(sizeof(int) * G->vexNum);
    int *d = (int *)malloc(sizeof(int) * G->vexNum);
    for (i = 0; i < G->vexNum; i++){
        if (G->arcs[index][i] > 0 && G->arcs[index][i] != MAX){
            s[i] = 0;
            p[i] = index;
            d[i] = G->arcs[index][i];
        }
        else if (G->arcs[index][i] == 0){
            s[i] = 1;
            p[i] = -1;
            d[i] = 0;
        }
        else{
            s[i] = 0;
            p[i] = -1;
            d[i] = MAX;
        }
    }
    for (i = 0; i < G->vexNum - 1; i++){
        int index = getMin(G, d, s);
        s[index] = 1;
        for (j = 0; j < G->vexNum; j++){
            if (!s[j] && d[index] + G->arcs[index][j] < d[j]) {
                d[j] = d[index] + G->arcs[index][j];
                p[j] = index;
            }
        }
    }

    printf("The shortest path is:");
    int current = end;

    while(end != index){
        printf("%c-->",G->vexs[end]);
        end = p[end];
    }
    printf("%c\n",G->vexs[end]);
    printf("The shortest path spend is: %d\n",d[current]);
    free(s);
    free(p);
    free(d);
}

void read_file_to_arcs(char* filename,Graph *G){
	int i,j;
	FILE *file = fopen(filename, "r+");
    if (file == NULL) {
        file = fopen(filename, "w");
        if (file == NULL) printf("\n\t文件创建失败!");
    } else {
		fscanf(file,"%d",&G->vexNum);
		fscanf(file,"%d",&G->arcNum);
		for(i=0;i<G->vexNum;i++){
			for(j=0;j<G->vexNum;j++){
				fscanf(file,"%d",&G->arcs[i][j]);
			}
		}
	}
}
void read_scaner_to_arcs(Graph *G){
	int i,j,has_road;
	G->arcNum = 0;
	printf("请输入重要地点数:\n");
	scanf("%d",&G->vexNum);
	
	for(i=0;i<G->vexNum-1;i++){
		G->arcs[i][i] = 0;
		for(j=i+1;j<G->vexNum;j++){
			printf("============================================\n"); 
			printf("%d地到%d地是否有直达线路?(有填1,没有填0):\n",i+1,j+1);
			scanf("%d",&has_road);
			if(has_road==1){
				printf("请输入票价:\n");
				scanf("%d",&G->arcs[i][j]); 
				
				G->arcs[j][i] = G->arcs[i][j];
				printf("%d-->%d  票价:%d\n",i,j,G->arcs[i][j]);
				G->arcNum++;
			}else{
				G->arcs[i][j] = MAX;
				G->arcs[j][i] = G->arcs[i][j];
				printf("read success\n");
			}
		}
	}
	G->arcs[i][i] = 0;

}

void printGraph(Graph *G){
	int i,j;
	printf("%d %d\n",G->vexNum,G->arcNum);
	for(i=0;i<G->vexNum;i++){
		for(j=0;j<G->vexNum;j++){
			printf("%d ",G->arcs[i][j]);
		}
		printf("\n");
	}
}

void menu(){
	int i,start=0,end=0;
	Graph* G = initGraph(7);
	G->vexs = "1234567";
	system("cls");
	char ch;
	printf("*************欢迎来到交通指南系统*************\n");
	printf("-------------------菜单列表-------------------\n");
	printf("*            1.文件输入公交线路网            *\n");
	printf("*            2.控制台输入公交线路网          *\n");
	printf("*            0.退出程序                      *\n");
	printf("**********************************************\n");
	do{
		
		printf("请选择:");
		ch = getchar();
		fflush(stdin);
		int* visited = (int*)malloc(sizeof(int)*G->vexNum);
		for(i=0;i<G->vexNum;i++){
	        visited[i] = 0;
	    }
		switch(ch){
			case '1':
				read_file_to_arcs("4.txt",G);
				printf("=====================\n");
				printf("读入内容如下:\n");
				printGraph(G); 
				printf("=====================\n");
				printf("出发点:");
			    scanf("%d",&start);
			    printf("目的点:");
			    scanf("%d",&end);
				DFS(G,visited,0);
				printf("\n");
				dijkstra(G,start-1,end-1);
				printf("\n");
				printf("\n-------按任意键回到主菜单--------");
			  	getch();
			  	getchar();
				menu(); 
				break;
			case '2':
				read_scaner_to_arcs(G);
				printf("=====================\n");
				printf("读入内容如下:\n");
				printGraph(G); 
				printf("=====================\n");
				printf("出发点:");
			    scanf("%d",&start);
			    printf("目的点:");
			    scanf("%d",&end);
				DFS(G,visited,0);
				printf("\n");
				dijkstra(G,start-1,end-1);
				printf("\n");
				printf("\n-------按任意键回到主菜单--------");
			  	getch();
			  	getchar();
				menu(); 
				break;
			case '0':
				exit(0);
		}
		
	    
	}while(ch!='0');
	freeGraph(G); 
}

int main(){
	menu();	
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式(二十二):行为型之备忘录模式

设计模式系列文章 设计模式(一)&#xff1a;创建型之单例模式 设计模式(二、三)&#xff1a;创建型之工厂方法和抽象工厂模式 设计模式(四)&#xff1a;创建型之原型模式 设计模式(五)&#xff1a;创建型之建造者模式 设计模式(六)&#xff1a;结构型之代理模式 设计模式…

【C】转义字符以及注释的介绍

转义字符 转义字符顾名思义就是转变意思。就是把原来字符的意思转变了&#xff0c;让它拥有别的意思。 如果我们想要在屏幕上打印&#xff1a;c:\code:\test.c 这样一串文字的话&#xff0c;我们代码肯定会这样写&#xff1a; #include<stdio.h> int main() {printf(&q…

压缩感知入门④基于总体最小二乘的扰动压缩感知重构算法

压缩感知系列博客&#xff1a;压缩感知入门①从零开始压缩感知压缩感知入门②信号的稀疏表示和约束等距性压缩感知入门③基于ADMM的全变分正则化的压缩感知重构算法压缩感知入门④基于总体最小二乘的扰动压缩感知重构算法 文章目录 1. Problem2. 仿真结果3. MATLAB算法4. 源码地…

Bean 的六种作用域

观前提示:本篇博客演示使用的 IDEA 版本为2021.3.3版本,使用的是Java8(又名jdk1.8) 前端使用VSCode(Visual Studio Code1.78.2) 电脑使用的操作系统版本为 Windows 10 目录 前言 Bean Spring 容器在初始化⼀个 Bean 的实例时&#xff0c;同时会指定该实例的作⽤域。 1. …

chatgpt赋能python:Python怎样能通过值找到键

Python怎样能通过值找到键 Python是一种高级编程语言&#xff0c;它在工业、医疗、科学、财务等多个行业中被广泛使用&#xff0c;是数据科学、人工智能和深度学习等领域的首选语言。在Python编程中&#xff0c;有时候我们需要在字典中根据值查询对应的键&#xff0c;本文将介…

chatgpt赋能python:Python排序算法大全

Python排序算法大全 导言 排序是程序员日常工作中最常见的操作之一。Python提供了许多实现排序算法的库和函数&#xff0c;本文将带您了解这些排序方法。 初级排序算法 冒泡排序 Bubble Sort 冒泡排序是一种简单的排序算法。它通过不断交换相邻的元素&#xff0c;将大的元…

【微服务架构设计和实现】4.2 服务边界的定义和划分

第一章&#xff1a;【云原生概念和技术】 第二章&#xff1a;【容器化应用程序设计和开发】 第三章&#xff1a;【基于容器的部署、管理和扩展】 第四章&#xff1a;【4.1 微服务架构概述和设计原则】 4.2 服务边界的定义和划分 4.2 服务边界的定义和划分4.2.1 什么是服务边…

docker创建Ubuntu,Ubuntu创建桌面环境,本机使用VNC连接

题目&#xff1a;docker创建Ubuntu&#xff0c;Ubuntu创建桌面环境&#xff0c;本机使用VNC连接 文章目录 前言docker创建基于Ubuntu:20.04的容器使用ssh连接容器容器安装桌面环境本机电脑使用VNC连接测试用python来创建的ui能否显示坑参考 前言 为什么我想要用ubuntu的桌面环…

RFID课程要点总结_2 Identification

2. Identification 简单说RFID就是物体上贴tag&#xff0c;用reader上的antenna去读取&#xff0c;这三个是主要组成。 Reader’s function Energy supply: 比如有的标签自身不带能量需要reader提供信号中蕴含的能量 Communication: 最基本的功能&#xff0c;和tag识别&…

Flink CDC、OGG、Debezium等基于日志开源CDC方案对比

先上一张图&#xff0c;后面再慢慢介绍&#xff1a; CDC概述 CDC 的全称是 Change Data Capture &#xff0c;在广义的概念上&#xff0c;只要能捕获数据变更的技术&#xff0c;我们都可以称为 CDC 。我们目前通常描述的CDC 技术主要面向数据库的变更&#xff0c;是一种用于捕…

56、基于51单片机智能医院红外点滴检测输液器报警系统设计(程序+原理图+PCB源文件+参考论文+参考PPT+元器件清单等)

引 言 目前&#xff0c;国际上每年每人的静脉输液量平均为2.5-3.3瓶&#xff0c;就我国而言&#xff0c;每年每人平均输液量8瓶&#xff0c;总量超过100亿瓶&#xff0c;其中每年约有39万人死于输液不良反应 。在如今新冠肺炎疫情持续的情况下&#xff0c;静脉输液仍是临床医学…

chatgpt赋能python:Python中如何选取list13列

Python中如何选取list 1 3列 介绍 对于SEO优化来说&#xff0c;选取适当的数据是至关重要的一步。Python是一门强大的编程语言&#xff0c;可以帮助人们快速而准确地处理数据&#xff0c;进而选择最佳数据进行SEO。在Python中&#xff0c;我们可以使用一些简单的方法来选择li…

kubespray部署kubernetes集群

kubespray部署kubernetes集群 1、kubespray简介 Kubespray 是开源的部署生产级别 Kubernetes 集群的项目&#xff0c;它整合了 Ansible 作为部署的工具。 可以部署在 AWS&#xff0c;GCE&#xff0c;Azure&#xff0c;OpenStack&#xff0c;vSphere&#xff0c;Packet(Bare m…

马原否定之否定观点

事物普遍联系和发展 事物之间的普遍联系的 答案B C考察的是联系的条件性 1.联系对事物的发展有制约和支撑的作用 2.联系的条件可以相互转化 所以我们可以将不利条件转化成有利条件 3.建立联系必须尊重客观规律。 对立统一是事物发展的根本规律、 唯物辩证法揭示了事物发展一…

ELK日志收集系统集群实验

目录 一、实验拓扑 二、环境配置 (一)设置各个主机的IP地址为拓扑中的静态IP&#xff0c;在两个节点中修改主机名为node1和node2并设置hosts文件 1、在虚拟机node1上操作 2、在虚拟机node2上操作 3、测试node1与node2的通联性 三、 安装node1与node2节点的elasticsearch…

大数据Doris(四十四):kafka json 数组格式数据导入到Doris

文章目录 kafka json 数组格式数据导入到Doris 一、创建 Doris 表 二、创建 Kafka topic

[论文笔记]Bidirectional LSTM-CRF Models for Sequence Tagging

引言 本文是论文Bidirectional LSTM-CRF Models for Sequence Tagging的阅读笔记。这篇论文是15年发表的,比上次介绍的那篇还要早。 首次应用双向LSTM+CRF(BI-LSTM-CRF)到序列标注数据集。BI-LSTM-CRF模型可以有效地使用双向输入特征,也因为CRF层可以利用句子级标签信息。…

前端web入门-CSS-day06

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 一、标准流 二、Flex 布局 组成 主轴对齐方式 侧轴对齐方式 修改主轴方向 弹性伸缩比 弹性盒子换行…

chatgpt赋能python:Python如何优雅地退出程序执行

Python如何优雅地退出程序执行 Python是一种非常强大的编程语言&#xff0c;它易于学习和使用&#xff0c;并拥有许多有用的功能和库。在Python编程中&#xff0c;经常需要退出程序执行。本文将介绍一些Python中退出程序执行的方法&#xff0c;并探讨它们的优缺点。 1. 使用s…

数据库中的SQL是如何执行的?

简介 参考文献&#xff1a;03丨学会用数据库的方式思考SQL是如何执行的 以oracle和MySQL为例&#xff0c;讲解了sql是怎么被执行的&#xff0c;并且对比了执行过程中&#xff0c;oracle和MySQL的异同。 个人感觉&#xff0c;讲解的核心是SQL执行时的缓存机制。 Oracle中的s…