C++藍橋杯基礎篇(十一)

片頭

嗨~小伙伴們,大家好!今天我們來學習C++藍橋杯基礎篇(十一),學習類,結構體,指針相關知識,準備好了嗎?咱們開始咯~


一、類與結構體

類的定義:在C++中,類的定義是通過關鍵字"class"來完成的。一個類定義一舿數據的結構和方法。

class Person {private:				//私有的成員變量int age, height;double money;string books[100];public:					//公有的成員變量,成員函數string name;void say() {cout << "I'm " << name << endl;}void set_age(int a) {age = a;}int get_age() {return age;}void set_height(int h) {height = h;}int get_height() {return height;}void add_money(double x) {money += x;}
};

上面的例子定義了一個名為Person的類,包含了5個數據成員name,age,height,money,books,以及3個成員函數say()用來打招呼,set_age()用來設置年齡,get_age()用來獲取年齡,add_money()用來增加零錢的數量。可以通過實例化這個類來創建具體的對象并訪問其成員和方法。

類中的變量和函數被統一稱為類的成員變量。

private后面的內容是私有成員變量,在類的外部不能訪問;public后面的內容是公有成員變量,在類的外部可以訪問。

類的使用:

?正確示例代碼如下:

int main() {Person c;c.name = "小明";    //正確!訪問公有變量//c.age = 18;		//錯誤!訪問私有變量c.set_age(18);		//正確!set_age()是公有成員變量c.set_height(185);  //正確!set_height()是公有成員變量c.add_money(100);	//設置零錢為100塊c.say();cout << c.get_age() << endl;cout << c.get_height() << endl;return 0;
}

結構體和類的作用是一樣的。不同點在于,類默認是private,結構體默認是public。?


二、構造函數

結構體構造函數是一種特殊的函數,用于創建結構體并對其進行初始化。在C++中,結構體構造函數與類構造函數類似,用于初始化結構體的成員變量,可以通過傳入參數來指定初始值。結構體構造函數的名稱與結構體本身相同,不需要指定返回類型。

struct Person1 {int age, height;double money;Person1 () {};Person1(int _age, int _height, double _money) {age = _age;height = _height;money = _money;}
};int main() {Person1 p(18,185,100);    //調用有參構造cout << p.age << " " << p.height << " " << p.money << endl;Person1 a;                //調用無參構造cout << a.age << " " << a.height << " " << a.money << endl;return 0;
}

?此外,我們還可以使用初始化列表來初始化成員變量

struct Person2 {int age, height;double money;Person2() {};  //無參構造Person2(int _age, int _height) :age(_age), height(_height) {}; //使用初始化列表構造Person2(int _age, int _height, double _money) :age(_age),height(_height),money(_money) {}
};int main() {Person2 p(18, 185, 100);cout << p.age << " " << p.height << " " << p.money << endl;Person2 a;cout << a.age << " " << a.height << " " << a.money << endl;return 0;
}

三、指針和引用

指針指向存放變量的值的地址。因此,我們可以通過指針來修改變量的值。

int main() {int a = 10;int* p = &a;*p += 5;cout << *p << endl;		//15cout << a << endl;		//15return 0;
}

上面代碼中,指針p存放的是a的地址,修改*p的值,a的值也會被修改。

數組名是一種特殊的指針。指針可以做運算。

int main() {char c;int a[5] = { 1,2,3,4,5 };printf("%p\n", &c);printf("%p\n", &a);return 0;
}

我們將數組a中每個元素的地址都打印一遍:

int main() {char c;int a[5] = { 1,2,3,4,5 };printf("字符c的地址為: %p\n", &c);printf("數組名a的地址為: %p\n", &a);for (int i = 0; i < 5; i++) {printf("a[%d] = %p\n",i, &a[i]);}cout << endl;return 0;
}

由此,我們發現,數組名和首元素的地址相同。數組名 = 首元素地址。每個地址之間相差4個字節,因為是int類型的數組,每個int類型的整數占4個字節。

我們還可以通過指針+1來訪問下一個元素

int main() {char c;int a[5] = { 1,2,3,4,5 };int* p = a;		//p代表首元素a[0]的地址cout << p << endl;cout << p + 1 << endl;return 0;
}

?因此,如果我們想直接訪問a[2]的話,也可以寫成 *(p+2)

int main() {int a[5] = { 1,2,3,4,5 };int* p = a;					//p代表首元素a[0]的地址cout << p << endl;			//a[0]的地址cout << *p << endl;			//a[0]的值cout << p + 1 << endl;		//a[1]的地址cout << *(p + 1) << endl;	//a[1]的值cout << p + 2 << endl;		//a[2]的地址cout << *(p + 2) << endl;	//a[2]的值return 0;
}

因此,遍歷整個數組的代碼如下:

int main() {int a[5] = { 1,2,3,4,5 };int* p = a;//之前的for (int i = 0; i < 5; i++) {cout << a[i] << " ";}cout << endl;//現在的for (int i = 0; i < 5; i++) {cout << *(p + i) << " ";}return 0;
}

同理,輸出可以用指針實現,那么輸入也可以:

int main() {char c;int a[5] = { 1,2,3,4,5 };scanf("%d", a + 1);		//輸入a[1]的值//相當于 scanf("%d",&a[1]);//因為數組名 = 首元素的地址//數組名+1 = 下一個元素的地址for (auto e : a) {cout << e << " ";}cout << endl;return 0;
}

那么,難道指針只能進行加法運算碼?不是的~ 可以進行減法運算

int main() {int a[5] = { 1,2,3,4,5 };int* p = &a[0];int* q = &a[2];cout << q - p << endl; //2return 0;
}

引用和指針類似,相當于給變量起個別名。

int main() {int a = 10;int& p = a;			 //p是a的別名p += 5;cout << p << endl;   //p的值被修改為15cout << a << endl;	 //a的值被修改為15return 0;
}


?四、鏈表

單鏈表在C語言中可以定義為一個結構體,其中包含一個指向下一個節點的指針。

// 定義單鏈表節點
struct Node {int data; // 節點數據struct Node *next; // 指向下一個節點的指針
};// 定義單鏈表
struct LinkedList {struct Node *head; // 頭節點指針
};

在這個定義中,struct Node 代表單鏈表的節點,包含節點的數據和指向下一節點的指針。struct LinkedList 代表整個單鏈表,其中包含一個頭節點指針 head,指向鏈表的第一個節點。

struct Node {int val;		//節點里面的值Node* next;		//指向下一節點的next指針Node(int _val):val(_val),next(NULL){}
};int main() {Node* p = new Node(1);   //創建p節點Node* q = new Node(2);   //創建q節點Node* o = new Node(3);	 //創建o節點p->next = q;			 //p節點的next指針指向q節點q->next = o;			 //q節點的next指針指向o節點Node* pcur = p;			 //pcur節點從第1個節點p開始//鏈表的遍歷方式for (Node* i = pcur; i != NULL; i = i->next) {cout << i->val << " -->" << " ";}cout << "NULL" << endl;return 0;
}

? 如何在鏈表中添加節點呢?并且添加在第一個位置,也就是頭插

	Node* p = new Node(1);   //創建p節點Node* q = new Node(2);   //創建q節點Node* o = new Node(3);	 //創建o節點p->next = q;			 //p節點的next指針指向q節點q->next = o;			 //q節點的next指針指向o節點Node* head = p;			 //pcur節點從第1個節點p開始//添加節點Node* u = new Node(4);u->next = head;head = u;

那么如何刪除節點呢?刪除鏈表中第2個節點

	Node* p = new Node(1);   //創建p節點Node* q = new Node(2);   //創建q節點Node* o = new Node(3);	 //創建o節點p->next = q;			 //p節點的next指針指向q節點q->next = o;			 //q節點的next指針指向o節點Node* head = p;			 //pcur節點從第1個節點p開始//刪除節點head->next = head->next->next;


五、習題
第1題? 斐波那契數列

錯誤代碼如下:

class Solution {
public:int Fibonacci(int n) {if (n <= 2) return 1;		//錯誤,這是第0項為1return Fibonacci(n - 1) + Fibonacci(n - 2);}
};

為啥錯了呢?因為,題目告訴我們從0開始,第0項為0

因此,正確代碼如下:

//f(0)=0,f(1)=1
//f(2)=f(0)+f(1)=1
//f(3)=f(1)+f(2)=2class Solution {
public:int Fibonacci(int n) {if (n <= 1) return n;	//當n==0,返回0	//當n==1,返回1return Fibonacci(n - 1) + Fibonacci(n - 2); //從n==2開始,都滿足這個規律}
};

第2題? 替換空格

代碼如下:

class Solution {
public:string replaceSpaces(string& str) {string res;			  //定義res字符串,用來保存最后結果for (auto c : str) {if (c == ' ') res += "%20";else res += c;}return res;}
};

第3題? 求1+2+3+...+n

題目要求我們不能使用乘除法、for、while、if、else、switch、case以及條件判斷語句(A?B:C)?,那么我們可以使用短路與&&和遞歸來解決此類問題。

sum(n) = n+sum(n-1),但是要注意終止條件,由于求的是 1+2+3+....+n 的和,所以需要在n=0的時候跳出遞歸。但是題目要求不能使用if,while等分支判斷,可以考慮利用&&短路運算來終止判斷。

代碼如下:

方法一:

class Solution {
public:int getSum(int n) {int res = n;n > 0 && (res += getSum(n - 1) + n);  //短路與&&//只要左邊的表達式錯誤,那么右邊也不會再執行//利用短路與&&終止遞歸return 0;}
};

方法二:我們還可以采用函數遞歸來解決。在外部定義遞歸函數,內部調用即可。

//調用函數
class Solution {
public:int getSum(int n) {return f(n);}int f(int n) {if (n == 0) return 0;return f(n - 1) + n;}
};

第4題? 在O(1)時間刪除鏈表結點

代碼如下:

struct ListNode {int val;ListNode* next;ListNode(int x):val(x),next(NULL){}
};class Solution {
public:void deleteNode(ListNode* node) {node->val = node->next->val;	//偽裝成下一個點node->next = node->next->next;	//將下一個點刪掉}
};

?還有一種更簡便的方法:

struct ListNode {int val;ListNode* next;ListNode(int x):val(x),next(NULL){}
};class Solution {
public:void deleteNode(ListNode* node) {*(node) = *(node->next);}
};
第5題? 合并兩個排序的鏈表

這道題,我們先來一種易理解的方法:

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {if (list1 == NULL)//如果list1為空,則返回list2return list2;if (list2 == NULL)//如果list2為空,則返回list1return list1;ListNode* l1 = list1;	//定義l1變量,指向list1ListNode* l2 = list2;	//定義l2變量,指向list2ListNode* newHead = NULL;  //定義新鏈表的頭節點ListNode* newTail = NULL;  //定義新鏈表的尾節點while (l1 && l2) {if (l1->val < l2->val) {//l1比l2小if (newHead == NULL) {//如果鏈表為空newHead = newTail = l1;}else {//鏈表不為空newTail->next = l1;newTail = l1;}l1 = l1->next;	//l1指向下一個節點}else {//l2比l1小if (newHead == NULL) {//如果鏈表為空newHead = newTail = NULL;}else {//鏈表不為空newTail->next = l2;newTail = l2;}l2 = l2->next;	//l2指向下一個節點}}if (l1) {//l1沒有遍歷完鏈表newTail->next = l1;}if (l2) {//l2沒有遍歷完鏈表newTail->next = l2;}return newHead;//返回頭節點
}

好啦,這道題我們基本上做完了。但是,看看這代碼,有重復冗余的部分,我們如何優化代碼呢?

有啦!我們可以定義一個哨兵節點,這個節點可以不存放數據,讓它指向新鏈表的頭節點

	ListNode* node = (ListNode*)malloc(sizeof(ListNode));		//創建一個哨兵節點ListNode* newHead = node;									//頭節點指向哨兵節點ListNode* newTail = node;									//尾節點指向哨兵節點

?中間的循環也要進行更改,不用判斷鏈表是否為空了

	while (l1 && l2) {if (l1->val < l2->val) {//l1比l2小newTail->next = l1;newTail = l1;l1 = l1->next;	//l1指向下一個節點}else {//l2比l1小newTail->next = l2;newTail = l2;l2 = l2->next;	//l2指向下一個節點}}

malloc了空間,但這塊空間實際上用不了,最后我們需要將哨兵節點釋放

	//malloc了空間,但這塊空間實際上用不了,最后我們需要將哨兵節點釋放ListNode* ret = newHead->next;free(newHead);return ret;		 //返回頭節點的下一個節點

?歐克,優化過的代碼如下:

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {if (list1 == NULL)//如果list1為空,則返回list2return list2;if (list2 == NULL)//如果list2為空,則返回list1return list1;ListNode* l1 = list1;	//定義l1變量,指向list1ListNode* l2 = list2;	//定義l2變量,指向list2ListNode* node = (ListNode*)malloc(sizeof(ListNode));		//創建一個哨兵節點ListNode* newHead = node;									//頭節點指向哨兵節點ListNode* newTail = node;									//尾節點指向哨兵節點while (l1 && l2) {if (l1->val < l2->val) {//l1比l2小newTail->next = l1;newTail = l1;l1 = l1->next;	//l1指向下一個節點}else {//l2比l1小newTail->next = l2;newTail = l2;l2 = l2->next;	//l2指向下一個節點}}if (l1) {//l1沒有遍歷完鏈表newTail->next = l1;}if (l2) {//l2沒有遍歷完鏈表newTail->next = l2;}//malloc了空間,但這塊空間實際上用不了,最后我們需要將哨兵節點釋放ListNode* ret = newHead->next;free(newHead);return ret;		 //返回頭節點的下一個節點
}

片尾

今天我們學習了相關類、結構體、指針相關知識,希望看完這篇文章能對友友們有所幫助!!!

點贊收藏加關注!!!

謝謝大家!!!

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

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

相關文章

css中實現border距離視圖左右兩側有距離

首先看效果圖 再看css是如何實現 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.main {background-color: aqua;display: block;width: 300px;padding: 0px 32px;box-sizing: border-box;}/…

Ubuntu 22.04 無法進入圖形界面的解決方法

Ubuntu 22.04 無法進入圖形界面&#xff0c;只能進入 tty&#xff0c;可能是由于圖形界面相關的配置或驅動程序出現了問題。以下是一些常見的解決方法&#xff1a; 1. 檢查圖形界面服務狀態 首先&#xff0c;檢查圖形界面服務&#xff08;通常是 gdm 或 lightdm&#xff09;的…

Tweak Power:全方位電腦系統優化的高效工具

在日常使用電腦時&#xff0c;系統性能的下降、垃圾文件的堆積以及硬盤的老化等問題常常困擾著用戶。為了提升電腦性能、優化系統運行&#xff0c;許多人會選擇系統優化工具。然而&#xff0c;國內一些系統優化軟件常常因為廣告過多或功能冗雜而讓人望而卻步。此時&#xff0c;…

深入淺出Bearer Token:解析工作原理及其在Vue、Uni-app與Java中的實現Demo

目錄 前言1. 基本知識2. Demo3. 實戰 前言 &#x1f91f; 找工作&#xff0c;來萬碼優才&#xff1a;&#x1f449; #小程序://萬碼優才/r6rqmzDaXpYkJZF 1. 基本知識 Bearer Token是一種基于Token的認證機制&#xff0c;用于在HTTP請求中傳遞用戶的身份信息 應用于RESTful A…

kubernetes——part3-5 核心概念 Service

一、 service作用 使用kubernetes集群運行工作負載時&#xff0c;由于Pod經常處于用后即焚狀態&#xff0c;Pod經常被重新生成&#xff0c;因此Pod對應的IP地址也會經常變化&#xff0c;導致無法直接訪問Pod提供的服務&#xff0c;Kubernetes中使用了Service來解決這一問題&am…

從零開始 | C語言基礎刷題DAY1

?個人主頁&#xff1a;折枝寄北的博客 DAY1[2025.3.11] 1. 求兩個數的較大值2.從鍵盤輸入的兩個數的大小關系3.一個整數的奇偶性&#xff0c;請判斷4. 考試分數是否通過5.考試成績是否完美&#xff0c;請判斷 1. 求兩個數的較大值 題目&#xff1a; 寫一個函數求兩個整數的較…

開源模型時代的 AI 開發革命:Dify 技術深度解析

開源模型時代的AI開發革命&#xff1a;Dify技術深度解析 引言&#xff1a;AI開發的開源新紀元 在生成式AI技術突飛猛進的2025年&#xff0c;開源模型正成為推動行業創新的核心力量。據統計&#xff0c;全球超過80%的AI開發者正在使用開源模型構建應用&#xff0c;這一趨勢不僅…

Dify Web 前端獨立部署指南(與后端分離,獨立部署)

背景:單獨拆分前端出來部署,二開前后端 本文檔專注于 Dify Web 前端的部署流程和配置,適用于需要將項目部署到各種環境的運維人員和開發者。 1. 環境準備 1.1 部署環境要求 Node.js >= 18.17.0Nginx 或其他Web服務器(生產環境推薦)Docker(可選,用于容器化部署)1.…

《蒼穹外賣》SpringBoot后端開發項目核心知識點整理(DAY1 to DAY3)

目錄 一、在本地部署并啟動Nginx服務1. 解壓Nginx壓縮包2. 啟動Nginx服務3. 驗證Nginx是否啟動成功&#xff1a; 二、導入接口文檔1. 黑馬程序員提供的YApi平臺2. YApi Pro平臺3. 推薦工具&#xff1a;Apifox 三、Swagger1. 常用注解1.1 Api與ApiModel1.2 ApiModelProperty與Ap…

大數據hadoop課程筆記

1.課程導入 柯潔 Alpha Go是人工智能領域的里程碑。 深度學習 大模型deepseek chatgpt 大模型 和 大數據 之間有著非常緊密的關系。可以說&#xff0c;大數據是大模型發展的基石&#xff0c;而大模型是大數據價值挖掘的重要工具。 https://youtu.be/nN-VacxHUH8?sifj7Ltk…

架構學習第八周--Kubernetes博客搭建

目錄 一、整體架構 二、部署MySQL主從 三、部署Redis哨兵 四、部署WordPress 五、注意事項 一、整體架構 本項目為在一主三從的Kubernetes集群上部署WordPress博客。因為WordPress部分容器版本自行集成Apache和PHP服務&#xff0c;因此在Kubernetes上部署WordPress只需提供…

Application.OnTime如何引用帶參數的過程

Application.OnTime方法本身并不直接支持傳遞參數給被調用的過程。不過&#xff0c;有幾種方法可以間接實現這個需求。 方法1&#xff1a;使用單引號表達式 使用單引號表達式來傳遞參數時&#xff0c;不能在表達式中使用變量&#xff0c;需要把參數值直接寫到表達中&am…

網絡安全之tcpdump工具

引言 wireshark是一款非常不錯的抓包軟件&#xff0c;在圖形化界面占絕對統治地位&#xff1b;盡管其在字符界面下有些許選項可供使用&#xff0c;但終究不太方便&#xff0c;下面我再介紹一款NB的終端抓包工具 tcpdump 1、混雜模式 linux的網卡有混雜模式一說&#xff0c;當開…

VC++ 獲取目的IP的路由

GetBestRoute 函數獲取到目的IP的最佳匹配路由。 第一個參數為&#xff1a;destination&#xff08;目的IP&#xff09; 第二個參數為&#xff1a;source&#xff08;源IP&#xff09; 通常不需要指定第二個source&#xff0c;這個一般用來匹配具體某一個網卡接口路由的&…

JavaScript 模塊 vs C# 類:封裝邏輯的兩種哲學

引言 在現代軟件開發中&#xff0c;模塊化和面向對象設計是代碼組織的核心課題。本文通過對比 JavaScript 模塊&#xff08;ES6 Module&#xff09;與 C# 類&#xff08;Class&#xff09;的實現方式&#xff0c;探討兩種語言在封裝邏輯時的不同哲學&#xff0c;并給出實際應用…

大模型在甲狀腺癌診療全流程預測及方案制定中的應用研究

目錄 一、引言 1.1 研究背景與意義 1.2 研究目的與創新點 1.3 國內外研究現狀 二、大模型預測甲狀腺癌的理論基礎 2.1 甲狀腺癌相關醫學知識 2.2 大模型技術原理與特點 2.3 大模型在醫療領域的應用潛力 三、術前預測方案 3.1 預測模型構建 3.1.1 數據收集與預處理 …

electron+vue+webview內嵌網頁并注入js

vue內嵌網頁可以使用iframe實現內嵌網頁&#xff0c;但是只能通過postMessage間接通信&#xff0c;在electron環境下&#xff0c;vue可以直接使用webview來內嵌網頁&#xff0c;支持 executeJavaScript、postMessage、send 等豐富的通信機制。 使用 webview的優勢 性能更佳&…

leetcode日記(95)將有序數組轉換為二叉搜索樹

很簡單&#xff0c;感覺自己越來越適應數據結構題目了…… /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : va…

【threejs實戰教程一】初識Three.js,場景Scene、相機Camera、渲染器Renderer

Three.js是一個基于WebGL的JavaScript 3D圖形庫&#xff0c;用于在瀏覽器中創建和顯示3D內容 Three.js中最基礎的三個關鍵要素就是場景Scene、相機Camera、渲染器Renderer 通俗一點理解&#xff0c;場景就是我們生活中一個具體的場景&#xff0c;比如自然環境中的一棟建筑&…

【leetcode hot 100 138】隨機鏈表的復制

解決一&#xff1a;回溯 哈希表 本題要求我們對一個特殊的鏈表進行深拷貝。如果是普通鏈表&#xff0c;我們可以直接按照遍歷的順序創建鏈表節點。而本題中因為隨機指針的存在&#xff0c;當我們拷貝節點時&#xff0c;「當前節點的隨機指針指向的節點」可能還沒創建&#xf…