【數據結構 · 初階】- 順序表

目錄

一、線性表

二、順序表

1.實現動態順序表

SeqList.h

SeqList.c

Test.c

問題

經驗:free 出問題,2種可能性

解決問題

(2)尾刪

(3)頭插,頭刪

(4)在 pos 位插

(5)在 pos 位刪

(6)查找

2.整體代碼

SeqList.h

SeqList.c

test.c


一、線性表

線性表(linear list)是 n 個具有相同特性的數據元素的有限序列。 線性表是一種在實際中廣泛使用的數據結構,常見的線性表:順序表、鏈表、棧、隊列、字符串。

線性表在邏輯上是線性結構,也就說是連續的一條直線。但是在物理結構上并不一定是連續的,線性表在物理上存儲時,通常以數組鏈式結構的形式存儲。

二、順序表

順序表是用一段物理地址連續的存儲單元依次存儲數據元素的線性結構,一般情況下采用數組存儲。在數組上完成數據的增刪查改。

分類:
(1)靜態順序表:使用定長數組存儲元素
(2)動態順序表:使用動態開辟的數組存儲

靜態順序表只適用于確定知道需要存多少數據的場景。靜態順序表的定長數組導致N定大了,空間開多了浪費,開少了不夠用。所以現實中基本都是使用動態順序表,根據需要動態的分配空間大小

1.實現動態順序表

SeqList.h?

為方便替換成其他類型,我們將這些類型統一重命名為 SLDataType

typedef int SLDataType;
#define INIT_CAPACITY 4 // 初始化容量typedef struct SeqList
{SLDataType* a;int size;     // 有效數據個數int capacity; // 空間容量
}SL;// 增刪查改
void SLInit(SL* ps);
void SLDestroy(SL* ps);//打印順序表數據
void SLPrint(SL* ps);void SLPushBack(SL* ps, SLDataType x); // 尾插
void SLPopBack(SL* ps); // 尾刪
void SLPushFront(SL* ps, SLDataType x); // 頭插
void SLPopFront(SL* ps); // 頭刪// 擴容,2倍合適
void SLCheckCapacity(SL* ps);
SeqList.c
void SLInit(SL* ps)
{assert(ps);ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);if (ps->a == NULL){perror("malloc fail");return;}ps->size = 0;ps->capacity = INIT_CAPACITY;
}void SLDestroy(SL* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0; // 結合性,從右往左賦值
}void SLPrint(SL* ps)
{assert(ps);for (int i = 0; i < ps->size; ++i){printf("%d ", ps->a[i]);}printf("\n");
}// 擴容,2倍合適
void SLCheckCapacity(SL* ps)
{assert(ps);if (ps->size == ps->capacity){SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2);//思考這里對不對if (tmp == NULL){perror("realloc fail");return;}ps->a = tmp; // 防止不是原地擴容ps->capacity *= 2;}}void SLPushBack(SL* ps, SLDataType x) // 尾插
{assert(ps);// 擴容  2倍合適SLCheckCapacity(ps);ps->a[ps->size++] = x;
}
Test.c
void TestSeqList1()
{SL s;SLInit(&s);SLPushBack(&s, 1);SLPushBack(&s, 2);SLPushBack(&s, 3);SLPushBack(&s, 4);SLPrint(&s);SLDestroy(&s);
}int main()
{TestSeqList1();return 0;
}

運行上面的代碼,順序表里插入1234:,程序沒毛病


問題

void TestSeqList1()
{SL s;SLInit(&s);SLPushBack(&s, 1);SLPushBack(&s, 2);SLPushBack(&s, 3);SLPushBack(&s, 4);SLPushBack(&s, 5);SLPrint(&s);SLDestroy(&s);
}

奇怪的事情發生了:

SLPushBack(&s, 6);
SLPushBack(&s, 7);

奇怪的事情又發生了:??? 光標在閃

這里反反復復調試都發現不了問題


經驗:free 出問題,2種可能性

(1)野指針 或 位置不對。這種情況不多
eg:申請一塊空間,從中間位置釋放,報錯。(應該從起始位置釋放)
(2)指針指向的空間(數組)上面,可能有越界。

  • 下標越界
  • 開少了

解決問題

realloc 返回的是地址,->a,a 我們沒有動過,動的都是 a 指向的內容
free 有時候出問題,通常不是free ( ) 里面有問題,而是前面有越界

仔細查,動空間的只有 SLPushBack(? ? )

// 擴容,2倍合適
void SLCheckCapacity(SL* ps)
{assert(ps);if (ps->size == ps->capacity){SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2);//思考這里對不對if (tmp == NULL){perror("realloc fail");return;}ps->a = tmp; // 防止原地擴容ps->capacity *= 2;}}void SLPushBack(SL* ps, SLDataType x) // 尾插
{assert(ps);// 擴容  2倍合適SLCheckCapacity(ps);ps->a[ps->size++] = x;
}

ps->a[ps->size++] = x; 邏輯沒有問題,問題大概率出現在擴容

先看下標越界了嗎?size 沒有越界的可能性

還有一種可能是開少了。
你以為你原來是 4 個,擴容到 8 個。你以為你有 8 個,實際上沒有 8 個。你當成 8 個訪問的呀,就越了。

8 個 SLDataType 是 4*8=32 字節。
ps->capacity * 2 這里是 4*2=8 字節


正確寫法:

// 擴容  2倍合適
void SLCheckCapacity(SL* ps)
{assert(ps);if (ps->size == ps->capacity){SLDataType* tmp = (SLDataType*)realloc(ps->a, sizeof(SLDataType) * ps->capacity * 2);if (tmp == NULL){perror("realloc fail");return;}ps->a = tmp;ps->capacity *= 2;}
}void SLPushBack(SL* ps, SLDataType x) // 尾插
{assert(ps);SLCheckCapacity(ps);ps->a[ps->size++] = x;
}

?問題解決

(2)尾刪

void SLPopBack(SL* ps) // 尾刪
{assert(ps);//ps->a[ps->size - 1] = 0; 加上沒用ps->size--;
}

由 size 遍例順序表,size --?后,前 size-1個是有效數據,第 size 個訪問不到了

注意:這里不用釋放,一部分一部分釋放會報錯。
但是不用擔心,當我們不用這個順序表時會?SLDestroy(&s) ; 空間還是會釋放的


刪空了還刪,會報錯。所以要檢查

void SLPopBack(SL* ps) // 尾刪
{assert(ps);// 溫柔的檢查if (ps->size == 0)return;ps->size--;
}

斷言 assert 會直接告訴你哪出錯了,并且終止掉程序

void SLPopBack(SL* ps) // 尾刪
{assert(ps);// 暴力檢查assert(ps->size > 0);ps->size--;
}

(3)頭插,頭刪

要挪動數據,以實現順序表連續性
順序表尾插,尾刪效率不錯。頭插,頭刪效率不太行。但有時候就要頭插,頭刪

void SLPushFront(SL* ps, SLDataType x) // 頭插
{assert(ps);SLCheckCapacity(ps);//挪動memmove(&(ps->a[1]), &(ps->a[0]), sizeof(SLDataType) * ps->size);//頭插ps->a[0] = x;ps->size++;
}void SLPopFront(SL* ps) // 頭刪
{assert(ps);assert(ps->size > 0);memmove(&(ps->a[0]), &(ps->a[1]), sizeof(SLDataType) * ps->size);ps->size--;
}

我們發現:插入N個數據。尾插時間復雜度:O(N)? ?? 頭插時間復雜度:O(N^2)
頭插1萬個數據,要執行1億次。所以,盡量避免使用頭插

疑問:為什么頭插用memmove庫函數了,時間復雜度還是O(N^2)
答:雖然我們用的是庫函數,一步到位,沒有用模擬實現。我們分析它的時間復雜度,還是要看到本質,本質就是模擬實現,通過模擬實現分析它的時間復雜度。

本質:

void SLPushFront(SL* ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);int end = ps->size - 1;while (end >= 0){ps->a[end + 1] = ps->a[end];--end;}ps->a[0] = x;ps->size++;
}

可以看到,頭插1個數據,執行N次,時間復雜度O(N)。頭插N個數據,執行N^2次,時間復雜度O(N^2)? 從模擬實現的角度看,它是一個等差數列

(4)在 pos 位插

// 順序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);// 插入時 = size 相當于尾插SLCheckCapacity(ps);//挪動memmove(&(ps->a[pos + 1]), &(ps->a[pos]), sizeof(SLDataType) * (ps->size - pos));//插入ps->a[pos] = x;ps->size++;
}

我們可以簡化頭插(在第0位),尾插(在第size位)。

void SLPushBack(SL* ps, SLDataType x) // 尾插
{assert(ps);/*SLCheckCapacity(ps);ps->a[ps->size++] = x;*/SLInsert(ps, ps->size, x);
}void SLPushFront(SL* ps, SLDataType x) // 頭插
{assert(ps);/*SLCheckCapacity(ps);//挪動memmove(&(ps->a[1]), &(ps->a[0]), sizeof(SLDataType) * ps->size);//頭插ps->a[0] = x;ps->size++;*/SLInsert(ps, 0, x);
}

(5)在 pos 位刪

// 順序表刪除pos位置的值
void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);//覆蓋memmove(&(ps->a[pos]), &(ps->a[pos + 1]), sizeof(SLDataType) * (ps->size - pos - 1));ps->size--;
}

可以簡化 頭刪,尾刪 的代碼。

void SLPopBack(SL* ps) // 尾刪
{assert(ps);/*// 暴力檢查assert(ps->size > 0);溫柔的檢查//if (ps->size == 0)//	return;ps->size--;*/SLErase(ps, ps->size - 1);
}void SLPopFront(SL* ps) // 頭刪
{assert(ps);/*assert(ps->size > 0);memmove(&(ps->a[0]), &(ps->a[1]), sizeof(SLDataType) * ps->size);ps->size--;*/SLErase(ps, 0);
}

疑問:用這個新的代碼尾刪,假設現在size = 8,根據上面代碼,最大容量 capacity 也 = 8。要尾刪,刪下標為7的位置,傳給 pos,pos+1 = 8 。SLErase 里面 &(ps->a[pos + 1]) 不會越界訪問嗎?
解答:這時要 memmove 移動?ps->size - pos - 1 = 0 個字節。我們看 memmove 模擬實現:num 是要移動的字節個數,這里 num = 0 ,循環沒進去,也就不存在越界訪問了

(6)查找

//順序表查找
int SLFind(SL* ps, SLDataType x)
{assert(ps);for (int i = 0; i < ps->size; i++){if (x == ps->a[i]){return i;}}return -1;
}

問:為什么刪除后,不用 realloc 回收一部分內存的使用權?
答:當擴容時,realloc 開內存,分為異地擴容,本地擴容。想要新開辟空間,如果原空間后面的大小夠,就本地擴容,效率高。后面大小不夠,就異地擴容,效率低
而現代計算機內存空間的數量很多,不怕浪費,為保證運行效率,寧愿占著茅坑不拉屎。

當我們確認不再使用時,也會 SLDestroy 釋放全部空間

問:為什么不寫菜單?
答:數據結構部分,菜單沒有什么價值。而且不好調試。菜單一般在命令行程序,控制數據庫的服務器,會輸入選項(指令去控制)。
寫菜單的話,也不要一上來就寫菜單。先在 test.c 里寫一組一組測試 ,測的沒問題了,再寫菜單

2.整體代碼

SeqList.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int SLDataType;
#define INIT_CAPACITY 4 // 初始化容量typedef struct SeqList
{SLDataType* a;int size;     // 有效數據個數int capacity; // 空間容量
}SL;// 增刪查改
void SLInit(SL* ps);
void SLDestroy(SL* ps);//打印順序表數據
void SLPrint(SL* ps);void SLPushBack(SL* ps, SLDataType x); // 尾插
void SLPopBack(SL* ps); // 尾刪
void SLPushFront(SL* ps, SLDataType x); // 頭插
void SLPopFront(SL* ps); // 頭刪// 順序表查找
int SLFind(SL* ps, SLDataType x);
// 順序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x);
// 順序表刪除pos位置的值
void SLErase(SL* ps, int pos);// 擴容,2倍合適
void SLCheckCapacity(SL* ps);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"void SLInit(SL* ps)
{assert(ps);ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);if (ps->a == NULL){perror("malloc fail");return;}ps->size = 0;ps->capacity = INIT_CAPACITY;
}void SLDestroy(SL* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0; // 結合性,從右往左賦值
}void SLPrint(SL* ps)
{assert(ps);for (int i = 0; i < ps->size; ++i){printf("%d ", ps->a[i]);}printf("\n");
}// 擴容  2倍合適
void SLCheckCapacity(SL* ps)
{assert(ps);if (ps->size == ps->capacity){SLDataType* tmp = (SLDataType*)realloc(ps->a, sizeof(SLDataType) * ps->capacity * 2);if (tmp == NULL){perror("realloc fail");return;}ps->a = tmp;ps->capacity *= 2;}
}void SLPushBack(SL* ps, SLDataType x) // 尾插
{assert(ps);/*SLCheckCapacity(ps);ps->a[ps->size++] = x;*/SLInsert(ps, ps->size, x);
}void SLPopBack(SL* ps) // 尾刪
{assert(ps);/*// 暴力檢查assert(ps->size > 0);溫柔的檢查//if (ps->size == 0)//	return;ps->size--;*/SLErase(ps, ps->size - 1);
}void SLPushFront(SL* ps, SLDataType x) // 頭插
{assert(ps);/*SLCheckCapacity(ps);//挪動memmove(&(ps->a[1]), &(ps->a[0]), sizeof(SLDataType) * ps->size);//頭插ps->a[0] = x;ps->size++;*/SLInsert(ps, 0, x);
}void SLPopFront(SL* ps) // 頭刪
{assert(ps);/*assert(ps->size > 0);memmove(&(ps->a[0]), &(ps->a[1]), sizeof(SLDataType) * ps->size);ps->size--;*/SLErase(ps, 0);
}//順序表查找
int SLFind(SL* ps, SLDataType x)
{assert(ps);for (int i = 0; i < ps->size; i++){if (x == ps->a[i]){return i;}}return -1;
}// 順序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);// 插入時 = size 相當于尾插SLCheckCapacity(ps);//挪動memmove(&(ps->a[pos + 1]), &(ps->a[pos]), sizeof(SLDataType) * (ps->size - pos));//插入ps->a[pos] = x;ps->size++;
}// 順序表刪除pos位置的值
void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);//覆蓋memmove(&(ps->a[pos]), &(ps->a[pos + 1]), sizeof(SLDataType) * (ps->size - pos - 1));ps->size--;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"void TestSeqList1()//第一組測試用例
{SL s;SLInit(&s);SLPushBack(&s, 1);SLPushBack(&s, 2);SLPushBack(&s, 3);SLPushBack(&s, 4);SLPushBack(&s, 5);SLPushBack(&s, 6);SLPushBack(&s, 7);SLPushBack(&s, 8);SLPrint(&s);SLPopBack(&s);SLPopBack(&s);SLPrint(&s);SLPushFront(&s, 9);SLPushFront(&s, 10);SLPushFront(&s, 11);SLPushFront(&s, 12);SLPushFront(&s, 13);SLPushFront(&s, 14);SLPrint(&s);SLPopFront(&s);SLPopFront(&s);SLPopFront(&s);SLPrint(&s);SLInsert(&s, 3, 30);SLPrint(&s);SLErase(&s, 3);SLPrint(&s);int pos = SLFind(&s, 3);if (pos == -1){printf("沒找到\n");}else{printf("找到了,下標是:%d", pos);}SLDestroy(&s);
}int main()
{TestSeqList1();return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/75464.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/75464.shtml
英文地址,請注明出處:http://en.pswp.cn/web/75464.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

windows主機中構建適用于K8S Operator開發環境

基于win 10 打造K8S應用開發環境&#xff08;wsl & kind&#xff09; 一、wsl子系統安裝 1.1 確認windows系統版本 cmd/powershell 或者win r 運行winver 操作系統要> 19044 1.2 開啟wsl功能 控制面板 -> 程序 -> 啟用或關閉Windows功能 開啟適用于Linu…

計算機視覺色彩空間全解析:RGB、HSV與Lab的實戰對比

計算機視覺色彩空間全解析&#xff1a;RGB、HSV與Lab的實戰對比 一、前言二、RGB 色彩空間?2.1 RGB 色彩空間原理?2.1.1 基本概念?2.1.2 顏色混合機制? 2.2 RGB 在計算機視覺中的應用?2.2.1 圖像讀取與顯示?2.2.2 顏色識別?2.2.3 RGB 色彩空間的局限性? 三、HSV 色彩空…

PyTorch多GPU訓練實戰:從零實現到ResNet-18模型

本文將介紹如何在PyTorch中實現多GPU訓練&#xff0c;涵蓋從零開始的手動實現和基于ResNet-18的簡潔實現。代碼完整可直接運行。 1. 環境準備與庫導入 import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2l from torchvisio…

micro介紹

micro介紹 Micro 的首要特點是易于安裝&#xff08;它只是一個靜態的二進制文件&#xff0c;沒有任何依賴關系&#xff09;和易于使用Micro 支持完整的插件系統。插件是用 Lua 編寫的&#xff0c;插件管理器可自動為你下載和安裝插件。使用簡單的 json 格式配置選項&#xff0…

Linux內核分頁——線性地址結構

每個進程通過一個指針&#xff08;即進程的mm_struct→pgd&#xff09;指向其專屬的頁全局目錄&#xff08;PGD&#xff09;&#xff0c;該目錄本身存儲在一個物理頁框中。這個頁框包含一個類型為pgd_t的數組&#xff0c;該類型是與架構相關的數據結構&#xff0c;定義在<as…

微信小程序開發:微信小程序上線發布與后續維護

微信小程序上線發布與后續維護研究 摘要 微信小程序作為移動互聯網的重要組成部分,其上線發布與后續維護是確保其穩定運行和持續優化的關鍵環節。本文從研究學者的角度出發,詳細探討了微信小程序的上線發布流程、后續維護策略以及數據分析與用戶反饋處理的方法。通過結合實…

分享一些使用DeepSeek的實際案例

文章目錄 前言職場辦公領域生活領域學習教育領域商業領域技術開發領域 前言 以下是一些使用 DeepSeek 的實際案例&#xff1a; DeepSeek使用手冊資源鏈接&#xff1a;https://pan.quark.cn/s/fa502d9eaee1 職場辦公領域 行業競品分析&#xff1a;剛入職的小李被領導要求一天內…

flink iceberg寫數據到hdfs,hive同步讀取

目錄 1、組件版本 環境變量配置 2、hadoop配置 hadoop-env.sh core-site.xml hdfs-site.xml mapred-site.xml yarn-site.xml 3、hive配置 hive-env.sh hive-site.xml HIVE LIB 原始JAR 4、flink配置集成HDFS和YARN 修改iceberg源碼 編譯iceberg-flink-runtime-1…

qq郵箱群發程序

1.界面設計 1.1 環境配置 在外部工具位置進行配置 1.2 UI界面設計 1.2.1 進入QT的UI設計界面 在pycharm中按順序點擊&#xff0c;進入UI編輯界面&#xff1a; 點擊第三步后進入QT的UI設計界面&#xff0c;通過點擊按鈕進行界面設計&#xff0c;設計后進行保存到當前Pycharm…

【C++游戲引擎開發】第10篇:AABB/OBB碰撞檢測

一、AABB(軸對齊包圍盒) 1.1 定義 ?最小點: m i n = ( x min , y min , z min ) \mathbf{min} = (x_{\text{min}}, y_{\text{min}}, z_{\text{min}}) min=(xmin?,ymin?,zmin?)?最大點: m a x = ( x max , y max , z max ) \mathbf{max} = (x_{\text{max}}, y_{\text{…

大模型是如何把向量解碼成文字輸出的

hidden state 向量 當我們把一句話輸入模型后&#xff0c;例如 “Hello world”&#xff1a; token IDs: [15496, 995]經過 Embedding Transformer 層后&#xff0c;會得到每個 token 的中間表示&#xff0c;形狀為&#xff1a; hidden_states: (batch_size, seq_len, hidd…

C++指針(三)

個人主頁:PingdiGuo_guo 收錄專欄&#xff1a;C干貨專欄 文章目錄 前言 1.字符指針 1.1字符指針的概念 1.2字符指針的用處 1.3字符指針的操作 1.3.1定義 1.3.2初始化 1.4字符指針使用注意事項 2.數組參數&#xff0c;指針參數 2.1數組參數 2.1.1數組參數的概念 2.1…

生命篇---心肺復蘇、AED除顫儀使用、海姆立克急救法、常見情況急救簡介

生命篇—心肺復蘇、AED除顫儀使用、海姆立克急救法、常見情況急救簡介 文章目錄 生命篇---心肺復蘇、AED除顫儀使用、海姆立克急救法、常見情況急救簡介一、前言二、急救1、心肺復蘇&#xff08;CPR&#xff09;&#xff08;1&#xff09;適用情況&#xff08;2&#xff09;操作…

基于神經環路的神經調控可增強遺忘型輕度認知障礙患者的延遲回憶能力

簡要總結 這篇文章提出了一種名為CcSi-MHAHGEL的框架&#xff0c;用于基于多站點、多圖譜fMRI的功能連接網絡&#xff08;FCN&#xff09;分析&#xff0c;以輔助自閉癥譜系障礙&#xff08;ASD&#xff09;的識別。該框架通過多視圖超邊感知的超圖嵌入學習方法&#xff0c;整合…

[WUSTCTF2020]level1

關鍵知識點&#xff1a;for匯編 ida64打開&#xff1a; 00400666 55 push rbp .text:0000000000400667 48 89 E5 mov rbp, rsp .text:000000000040066A 48 83 EC 30 sub rsp, 30h .text:000000…

cpp自學 day20(文件操作)

基本概念 程序運行時產生的數據都屬于臨時數據&#xff0c;程序一旦運行結束都會被釋放 通過文件可以將數據持久化 C中對文件操作需要包含頭文件 <fstream> 文件類型分為兩種&#xff1a; 文本文件 - 文件以文本的ASCII碼形式存儲在計算機中二進制文件 - 文件以文本的…

Gartner發布軟件供應鏈安全市場指南:軟件供應鏈安全工具的8個強制功能、9個通用功能及全球29家供應商

攻擊者的目標是由開源和商業軟件依賴項、第三方 API 和 DevOps 工具鏈組成的軟件供應鏈。軟件工程領導者可以使用軟件供應鏈安全工具來保護他們的軟件免受這些攻擊的連鎖影響。 主要發現 越來越多的軟件工程團隊現在負責解決軟件供應鏈安全 (SSCS) 需求。 軟件工件、開發人員身…

備賽藍橋杯-Python-考前突擊

額&#xff0c;&#xff0c;離藍橋杯開賽還有十個小時&#xff0c;最近因為考研復習節奏的問題&#xff0c;把藍橋杯的優先級后置了&#xff0c;突然才想起來還有一個藍橋杯呢。。 到目前為止python基本語法熟練了&#xff0c;再補充一些常用函數供明天考前再背背&#xff0c;算…

榕壹云外賣跑腿系統:基于Spring Boot+MySQL+UniApp的智慧生活服務平臺

項目背景與需求分析 隨著本地生活服務需求的爆發式增長&#xff0c;外賣、跑腿等即時配送服務成為現代都市的剛性需求。傳統平臺存在開發成本高、功能定制受限等問題&#xff0c;中小企業及創業團隊極需一款輕量級、可快速部署且支持二次開發的外賣跑腿系統。榕壹云外賣跑腿系統…

使用Docker安裝Gogs

1、拉取鏡像 docker pull gogs/gogs 2、運行容器 # 創建/var/gogs目錄 mkdir -p /var/gogs# 運行容器 # -d&#xff0c;后臺運行 # -p&#xff0c;端口映射&#xff1a;(宿主機端口:容器端口)->(10022:22)和(10880:3000) # -v&#xff0c;數據卷映射&#xff1a;(宿主機目…