【數據結構】二叉樹的鏈式結構--用C語言實現

1.二叉樹的鏈式結構

此前,我們通過數組(順序表)完成了二叉樹的順序存儲,并實現了二叉樹的基礎功能
那么,二叉樹還有沒有其他存儲方式呢?

前面我們學習了鏈表,它是一種線性結構,而二叉樹是一種非線性結構,但是通過思考,我們發現鏈表是通過next指針把一個一個的節點連接起來的,那么我們如何用相似的方式把二叉樹相應的節點連接起來呢?

//鏈表節點
typedef int LTDataType;//存儲的數據類型
typedef struct ListNode{LTDataType val;//數據值struct ListNode* next;//指向下一個節點
}LTNOde;

請添加圖片描述

通過觀察,我們發現二叉樹中,節點最大的度為2(每個節點最多連接兩個字節點),所以我們可以在鏈表節點的基礎上,再添加一個指針,用兩個指針來指向子節點,即可把整個二叉樹連接起來,形成一個鏈式結構

typedef int BTDataType;//存儲的數據類型
typedef struct BinaryTreeNode{LTDataType val;//數據值//指向左子節點struct BinaryTreeNode* left;//指向右子節點struct BinaryTreeNode* right;
}BTNode;

請添加圖片描述

2.鏈式結構的遍歷順序

鏈式結構的遍歷順序分為三種:前序遍歷、中序遍歷、后序遍歷

他們的順序都是相對于節點的
前序遍歷:節點-左節點-右節點
中序遍歷:左節點-節點-右節點
后續遍歷:左節點-右節點-節點

2.1.前序遍歷

從根節點開始遍歷,然后遍歷左子樹,最后遍歷右子樹
請添加圖片描述

  1. 根節點為A(當前前序遍歷結果:A)
  2. 再遍歷A的左子樹,繼續以根-左-右的順序遍歷,找到子樹的根節點B(當前前序遍歷結果:A-B)
  3. 遍歷B的左子樹,找到D,D沒有子樹了,所以B的左子樹遍歷完了(當前前序遍歷結果:A-B-D)
  4. B的根和左子樹遍歷完了,開始遍歷B的右子樹,找到節點E,此時A的左子樹遍歷完了(當前前序遍歷結果:A-B-D-E)
  5. A的根和左子樹遍歷完了,開始遍歷A的右子樹
  6. 找到A的子樹的根節點C(當前前序遍歷結果:A-B-D-E-C)
  7. 開始遍歷C的左子樹,找到F,C的左子樹遍歷完畢(當前前序遍歷結果:A-B-D-E-C-F)
  8. 開始遍歷C的右子樹,找到G,此時A的右子樹遍歷完畢(當前前序遍歷結果:A-B-D-E-C-F-G)
  9. 前序遍歷完成
  10. 最終結果為A-B-D-E-C-F-G

2.1.中序遍歷

從左子樹開始遍歷,再遍歷根節點,最后遍歷右子樹
請添加圖片描述
11. 先遍歷根節點A的左子樹,來到子樹中的根節點B,他有左子樹,繼續向下遍歷找他的左子樹,找到節點D,由于D沒有左子樹了,所以取D(當前中序遍歷結果:D-)
12. B的左子樹遍歷完了,遍歷根B本身,取B(當前中序遍歷結果:D-😎
13. 遍歷B的右子樹,找到E,E沒有子樹了,取E,B的右子樹遍歷完成(當前中序遍歷結果:D-B-E)
14. 此時A的左子樹遍歷完成,遍歷根A本身,取A(當前中序遍歷結果:D-B-E-A)
15. A的左子樹和根遍歷完成,遍歷A的右子樹來到C,C有左子樹,來到F,F沒有子樹了,取F(當前中序遍歷結果:D-B-E-A-F)
16. C的左子樹遍歷完成,遍歷根C本身,取節點C(當前中序遍歷結果:D-B-E-A-F-C)
17. C的左子樹和根遍歷完成,遍歷右子樹,找到節點G,它沒有子樹了,取G(當前中序遍歷結果:D-B-E-A-F-C-G)
18. A的右子樹遍歷完成,中序遍歷完畢
19. 最終結果為D-B-E-A-F-C-G

2.3.后序遍歷

從左子樹開始遍歷,再遍歷右子樹,最后遍歷根
請添加圖片描述

  1. 先遍歷根A的左子樹,找到節點B,B有左子樹,繼續遍歷,找到節點D,D沒有子樹了,取D(當前后序遍歷結果:D)
  2. B的左子樹遍歷完成,繼續遍歷它的右子樹,找到節點E,沒有子樹了,取E(當前后序遍歷結果:D-E)
  3. B的右子樹遍歷完成,取B本身(當前后序遍歷結果:D-E-B)
  4. A的左子樹遍歷完成,繼續遍歷A的右子樹,找到節點C,繼續遍歷C的左子樹,找到節點F,F沒有子樹了,取F(當前后序遍歷結果:D-E-B-F)
  5. C的左子樹遍歷完成,繼續遍歷它的右子樹,找到節點G,G沒有子樹了,取G(當前后序遍歷結果:D-E-B-F-G)
  6. C的左右子樹遍歷完成,取根C本身(當前后序遍歷結果:D-E-B-F-G-C)
  7. 此時A的左右子樹遍歷完成,取根A本身(當前后序遍歷結果:D-E-B-F-G-C-A)
  8. 后序遍歷完成,最終結果為D-E-B-F-G-C-A

3.二叉樹鏈式結構的實現

3.1.二叉樹節點結構的定義

一個結構體類型,成員包含存儲數據的值和分別指向左孩子和右孩子的左右指針

typedef char BTDataType;
typedef struct BinaryTreeNode
{BTDataType _data;struct BinaryTreeNode* _left;struct BinaryTreeNode* _right;
}BTNode;

3.2.創建節點

開辟一個節點大小的空間,把數據值存入該節點,返回這片空間的地址

BTNode* BTBuyNode(BTDataType x)
{BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));if(newNode == NULL){perror("malloc error!\n");return NULL;}newNode->_data = x;newNode->_left = newNode->_right = NULL;return newNode;
}

3.3.創建二叉樹

以前序遍歷為例,把數組中的數據,轉化為鏈式結構,存儲到二叉樹中

BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{if(*pi >= n || a[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = BTBuyNode(a[(*pi)++]);root->_left = BinaryTreeCreate(a, n, pi);root->_right = BinaryTreeCreate(a, n, pi);return root;
}

:形參中的pi必須傳指針(傳址調用),因為在遞歸過程中該形參會發生改變,如果采用傳值調用,該形參值不能被正常修改

3.4.二叉樹鏈式結構的銷毀

以后序遍歷的方式,先銷毀左右子樹,最后銷毀根節點(如果先銷毀根節點,那就找不到它的左右指針了,不能進行后續操作)

//左-右-根
void BinaryTreeDestory(BTNode** root)
{if(root == NULL || *root == NULL){return ;}//注:傳二級指針--指針的地址BinaryTreeDestory(&((*root)->_left));BinaryTreeDestory(&((*root)->_right));free(*root);*root = NULL;
}

3.5.節點總數

用遞歸的方式,返回左子樹的節點個數+右子樹的節點個數+根即可

int BinaryTreeSize(BTNode* root)
{if(root == NULL) return 0;return 1 + BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right);
}

3.6.葉子節點數

同樣用遞歸的方式,返回左子樹的葉子節點數+右子樹的葉子節點數,當該節點沒有左右子樹時,即為葉子節點,返回1

int BinaryTreeLeafSize(BTNode* root)
{if(root == NULL) return 0;if(!root->_left && !root->_right) return 1;return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}

3.7.返回第K層的節點數

同樣采用遞歸的方式,第K層節點數=根節點左子樹的第K-1層節點數+根節點的右子樹的第K-1層節點數,以此類推,每遞歸一次都減少一層···

int BinaryTreeLevelKSize(BTNode* root, int k)
{if(root == NULL || k < 1) return 0;if(k == 1) return 1;return BinaryTreeLevelKSize(root->_left, k-1) + BinaryTreeLevelKSize(root->_right, k-1);
}

3.8.查找節點

還是采用遞歸的方式,從根節點開始,遍歷每一個節點,直到遇到目標值,返回該節點的地址

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if(root == NULL) return NULL;if(root->_data == x) return root;BTNode* Left = BinaryTreeFind(root->_left, x);BTNode* Right = BinaryTreeFind(root->_right, x);if(Left) return Left;if(Right) return Right;return NULL;
}

3.9.前序遍歷

先打印根節點數據,再分別遞歸調用左子樹和右子樹

//根-左-右
void BinaryTreePrevOrder(BTNode* root)
{if(root == NULL) return;printf("%c ", root->_data);BinaryTreePrevOrder(root->_left);BinaryTreePrevOrder(root->_right);
}

3.10.中序遍歷

先遞歸調用左子樹,再打印根節點數據,最后遞歸調用右子樹

//左-根-右
void BinaryTreeInOrder(BTNode* root)
{if(root == NULL) return;BinaryTreeInOrder(root->_left);printf("%c ", root->_data);BinaryTreeInOrder(root->_right);
}

3.11.后序遍歷

先分別遞歸調用左右子樹,再打印根節點

//左-右-根
void BinaryTreePostOrder(BTNode* root)
{if(root == NULL) return;BinaryTreePostOrder(root->_left);BinaryTreePostOrder(root->_right);printf("%c ", root->_data);
}

3.12.層序遍歷

由于每一個節點都是通過指針連接的后繼節點,所以一層一層地調用是不現實的,這個時候我們可以借助隊列來實現層序遍歷:

創建一個隊列,先讓根節點入隊,取出隊列頭節點并打印,(如果有的話)讓它的左右孩子入隊,若隊列不為空,繼續取出隊頭節點并打印,讓它的左右孩子入隊,重復以上操作,直到隊列為空,則層序遍歷完成

隊列的實現(隊列的詳細講解):
Queue.h

//
//  Queue.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef struct BinaryTreeNode BTNode;
//隊列節點的結構
typedef struct QueueNode{BTNode* data;struct QueueNode* next;
}QueueNode;
//隊列的結構
typedef struct Queue{QueueNode* front;QueueNode* rear;
}Queue;//初始化隊列
void QueueInit(Queue* pq);//入隊
void QueuePush(Queue* pq, BTNode* x);//判空
bool QueueEmpty(Queue* pq);//出隊
void QueuePop(Queue* pq);//取隊頭
BTNode* QueueFront(Queue* pq);//銷毀隊列
void QueueDestroy(Queue* pq);

Queue.c

//
//  Queue.c
#include "Queue.h"
void QueueInit(Queue* pq)
{assert(pq);pq->front = pq->rear = NULL;
}void QueuePush(Queue* pq, BTNode* x)
{assert(pq);QueueNode* newQueNode = (QueueNode*)malloc(sizeof(QueueNode));if(newQueNode == NULL){perror("malloc fail!\n");return;}newQueNode->data = x;newQueNode->next = NULL;if(pq->front == NULL){pq->front = pq->rear = newQueNode;}else{pq->rear->next = newQueNode;pq->rear = newQueNode;}
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->front == NULL;
}void QueuePop(Queue* pq)
{assert(!QueueEmpty(pq));QueueNode* del = pq->front;pq->front = del->next;if(pq->front == NULL){pq->rear = NULL;}free(del);del = NULL;
}BTNode* QueueFront(Queue* pq)
{assert(!QueueEmpty(pq));return pq->front->data;
}
void QueueDestroy(Queue* pq)
{//節點QueueNode* pcur = pq->front;while(pcur){QueueNode* next= pcur->next;free(pcur);pcur = next;}//隊列首尾pq->front = pq->rear = NULL;
}

層序遍歷:

void BinaryTreeLevelOrder(BTNode* root)
{if(root == NULL) return;Queue q;QueueInit(&q);QueuePush(&q, root);while(!QueueEmpty(&q)){BTNode* top = QueueFront(&q);QueuePop(&q);printf("%c ", top->_data);if(top->_left) QueuePush(&q, top->_left);if(top->_right) QueuePush(&q, top->_right);}QueueDestroy(&q);
}

3.13.判斷是否為完全二叉樹

我們知道,完全二叉樹是由滿二叉樹得來的,在完全二叉樹中,最后一層以上的所有層次中,節點數都達到了最大值,而最后一層不一定,但一定滿足節點從左到右依次排列
因此,我們可以通過此性質,仿照層次遍歷的方式,通過隊列,來實現完全二叉樹的判定
:取隊頭時,不需要判斷左右孩子是否為空,直接入隊即可,當隊列頭節點為空時,跳出循環,此時判斷隊列后序數據是否存在非空值,若存在,則不是完全二叉樹,不存在,則是完全二叉樹

bool BinaryTreeComplete(BTNode* root)
{//當遍歷到空節點時 遞歸結束if(root == NULL) return true;Queue q;QueueInit(&q);while(!QueueEmpty(&q)){BTNode* top = QueueFront(&q);QueuePop(&q);//判斷是否為空節點if(top == NULL){break;}//左右子樹入隊QueuePush(&q, top->_left);QueuePush(&q, top->_right);}//檢查剩余元素while(!QueueEmpty(&q)){BTNode* top = QueueFront(&q);QueuePop(&q);//判斷隊頭元素if(top != NULL){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

4.完整代碼

Queue.h

//
//  Queue.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef struct BinaryTreeNode BTNode;
//隊列節點的結構
typedef struct QueueNode{BTNode* data;struct QueueNode* next;
}QueueNode;
//隊列的結構
typedef struct Queue{QueueNode* front;QueueNode* rear;
}Queue;//初始化隊列
void QueueInit(Queue* pq);//入隊
void QueuePush(Queue* pq, BTNode* x);//判空
bool QueueEmpty(Queue* pq);//出隊
void QueuePop(Queue* pq);//取隊頭
BTNode* QueueFront(Queue* pq);//銷毀隊列
void QueueDestroy(Queue* pq);

Tree.h

//
//  Tree.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>typedef char BTDataType;
typedef struct BinaryTreeNode
{BTDataType _data;struct BinaryTreeNode* _left;struct BinaryTreeNode* _right;
}BTNode;//創建節點
BTNode* BTBuyNode(BTDataType x);
// 通過前序遍歷的數組"ABD##E#H##CF##G##"構建二叉樹
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);
// 二叉樹銷毀
void BinaryTreeDestory(BTNode** root);
// 二叉樹節點個數
int BinaryTreeSize(BTNode* root);
// 二叉樹葉子節點個數
int BinaryTreeLeafSize(BTNode* root);
// 二叉樹第k層節點個數
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉樹查找值為x的節點
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉樹前序遍歷
void BinaryTreePrevOrder(BTNode* root);
// 二叉樹中序遍歷
void BinaryTreeInOrder(BTNode* root);
// 二叉樹后序遍歷
void BinaryTreePostOrder(BTNode* root);
// 層序遍歷
void BinaryTreeLevelOrder(BTNode* root);
// 判斷二叉樹是否是完全二叉樹
bool BinaryTreeComplete(BTNode* root);

Queue.c

//
//  Queue.c
#include "Queue.h"
void QueueInit(Queue* pq)
{assert(pq);pq->front = pq->rear = NULL;
}void QueuePush(Queue* pq, BTNode* x)
{assert(pq);QueueNode* newQueNode = (QueueNode*)malloc(sizeof(QueueNode));if(newQueNode == NULL){perror("malloc fail!\n");return;}newQueNode->data = x;newQueNode->next = NULL;if(pq->front == NULL){pq->front = pq->rear = newQueNode;}else{pq->rear->next = newQueNode;pq->rear = newQueNode;}
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->front == NULL;
}void QueuePop(Queue* pq)
{assert(!QueueEmpty(pq));QueueNode* del = pq->front;pq->front = del->next;if(pq->front == NULL){pq->rear = NULL;}free(del);del = NULL;
}BTNode* QueueFront(Queue* pq)
{assert(!QueueEmpty(pq));return pq->front->data;
}
void QueueDestroy(Queue* pq)
{//節點QueueNode* pcur = pq->front;while(pcur){QueueNode* next= pcur->next;free(pcur);pcur = next;}//隊列首尾pq->front = pq->rear = NULL;
}

Tree.c

//
//  Tree.c
#include "Tree.h"
#include "Queue.h"BTNode* BTBuyNode(BTDataType x)
{BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));if(newNode == NULL){perror("malloc error!\n");return NULL;}newNode->_data = x;newNode->_left = newNode->_right = NULL;return newNode;
}
//前序:根-左-右
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{if(*pi >= n || a[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = BTBuyNode(a[(*pi)++]);root->_left = BinaryTreeCreate(a, n, pi);root->_right = BinaryTreeCreate(a, n, pi);return root;
}//左-右-根
void BinaryTreeDestory(BTNode** root)
{if(root == NULL || *root == NULL){return ;}BinaryTreeDestory(&((*root)->_left));BinaryTreeDestory(&((*root)->_right));free(*root);*root = NULL;
}int BinaryTreeSize(BTNode* root)
{if(root == NULL) return 0;return 1 + BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right);
}int BinaryTreeLeafSize(BTNode* root)
{if(root == NULL) return 0;if(!root->_left && !root->_right) return 1;return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}int BinaryTreeLevelKSize(BTNode* root, int k)
{if(root == NULL || k < 1) return 0;if(k == 1) return 1;return BinaryTreeLevelKSize(root->_left, k-1) + BinaryTreeLevelKSize(root->_right, k-1);
}BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if(root == NULL) return NULL;if(root->_data == x) return root;BTNode* Left = BinaryTreeFind(root->_left, x);BTNode* Right = BinaryTreeFind(root->_right, x);if(Left) return Left;if(Right) return Right;return NULL;
}//根-左-右
void BinaryTreePrevOrder(BTNode* root)
{if(root == NULL) return;printf("%c ", root->_data);BinaryTreePrevOrder(root->_left);BinaryTreePrevOrder(root->_right);
}
//左-根-右
void BinaryTreeInOrder(BTNode* root)
{if(root == NULL) return;BinaryTreeInOrder(root->_left);printf("%c ", root->_data);BinaryTreeInOrder(root->_right);
}
//左-右-根
void BinaryTreePostOrder(BTNode* root)
{if(root == NULL) return;BinaryTreePostOrder(root->_left);BinaryTreePostOrder(root->_right);printf("%c ", root->_data);
}
//借助隊列來實現
void BinaryTreeLevelOrder(BTNode* root)
{if(root == NULL) return;Queue q;QueueInit(&q);QueuePush(&q, root);while(!QueueEmpty(&q)){BTNode* top = QueueFront(&q);QueuePop(&q);printf("%c ", top->_data);if(top->_left) QueuePush(&q, top->_left);if(top->_right) QueuePush(&q, top->_right);}QueueDestroy(&q);
}bool BinaryTreeComplete(BTNode* root)
{if(root == NULL) return true;Queue q;QueueInit(&q);while(!QueueEmpty(&q)){BTNode* top = QueueFront(&q);QueuePop(&q);if(top == NULL){break;}QueuePush(&q, top->_left);QueuePush(&q, top->_right);}while(!QueueEmpty(&q)){BTNode* top =QueueFront(&q);QueuePop(&q);if(top != NULL){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

main.c

//
//  main.c#include "Tree.h"
void test(void)
{char str[] = "ABD##E#H##CF##G##";int i = 0;int n = (int)strlen(str);BTNode* root = BinaryTreeCreate(str, n, &i);printf("二叉樹節點總數為:%d\n", BinaryTreeSize(root));printf("二叉樹葉子結點數為:%d\n", BinaryTreeLeafSize(root));printf("二叉樹第2層節點數為:%d\n", BinaryTreeLevelKSize(root, 2));printf("節點‘F’所在地址為:%p\n", BinaryTreeFind(root, 'F'));printf("二叉樹前序遍歷結果為:");BinaryTreePrevOrder(root);printf("\n");printf("二叉樹中序遍歷結果為:");BinaryTreeInOrder(root);printf("\n");printf("二叉樹后序遍歷結果為:");BinaryTreePostOrder(root);printf("\n");printf("二叉樹層序遍歷結果為:");BinaryTreeLevelOrder(root);printf("\n");BinaryTreeDestory(&root);
}
int main(void)
{test();return 0;
}

運行結果

請添加圖片描述

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

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

相關文章

java設計模式 -【適配器模式】

適配器模式的定義 適配器模式&#xff08;Adapter Pattern&#xff09;是一種結構型設計模式&#xff0c;用于解決接口不兼容問題。通過將一個類的接口轉換成客戶端期望的另一個接口&#xff0c;使原本因接口不匹配而無法工作的類能夠協同工作。 核心角色 目標接口&#xff08;…

前端,demo操作,增刪改查,to do list小項目

demo操作&#xff0c;html<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title>&l…

Spring AI 項目實戰(十九):Spring Boot + AI + Vue3 + OSS + DashScope 構建多模態視覺理解平臺(附完整源碼)

系列文章 序號 文章名稱 1 Spring AI 項目實戰(一):Spring AI 核心模塊入門 2 Spring AI 項目實戰(二):Spring Boot + AI + DeepSeek 深度實戰(附完整源碼) 3 Spring AI 項目實戰(三):Spring Boot + AI + DeepSeek 打造智能客服系統(附完整源碼) 4

在 Ubuntu 20.04.5 LTS 系統上安裝 Docker CE 26.1.4 完整指南

在 Ubuntu 20.04.5 LTS 系統上安裝 Docker CE 26.1.4 完整指南版本選擇說明 為什么選擇 Docker CE 26.1.4&#xff1f; 1. 版本穩定性和成熟度 Docker CE 26.1.4 是 2024 年 5 月發布的穩定版本&#xff0c;經過了充分的測試和驗證相比最新的 28.x 版本&#xff0c;26.1.4 在生…

避坑指南:Windows 11中 Docker 數據卷的存放位置

在 PowerShell 中使用 docker volume inspect 命令&#xff0c;輸出如下&#xff1a; [{"CreatedAt": "2025-07-23T01:00:45Z","Driver": "local","Labels": null,"Mountpoint": "/var/lib/docker/volumes/…

Hadoop大數據集群架構全解析

技術概述Hadoop的定義及其在大數據領域的地位Hadoop是由Apache基金會開發的開源分布式計算框架&#xff0c;基于Google的MapReduce和GFS論文思想實現&#xff0c;已成為大數據處理的事實標準。它通過分布式存儲和計算解決了傳統數據庫無法處理的海量數據存儲和分析問題&#xf…

【自動化測試】Selenium Python UI自動化測試實用教程

一、引言:Selenium與UI自動化測試基礎 1.1 Selenium簡介 Selenium是一個開源的Web應用自動化測試框架,支持多瀏覽器(Chrome、Firefox、Edge等)和多編程語言(Python、Java、JavaScript等),核心組件包括: WebDriver:通過瀏覽器原生API控制瀏覽器,模擬用戶操作(點擊、…

基于VSCode的nRF52840開發環境搭建

nRF52840是Nordic Semiconductor推出的一款功能強大的多協議SoC&#xff0c;廣泛應用于物聯網設備、可穿戴設備和低功耗藍牙產品開發。本篇文章將詳細介紹如何在VSCode中搭建完整的nRF52840開發環境&#xff0c;讓您能夠高效地進行嵌入式開發。 一、準備工作 VSCode&#xff1a…

GStreamer開發筆記(九):gst-rtcp-server安裝和部署實現簡單的rtsp-server服務器推流Demo

若該文為原創文章&#xff0c;轉載請注明原文出處 本文章博客地址&#xff1a;https://blog.csdn.net/qq21497936/article/details/149054288 長沙紅胖子Qt&#xff08;長沙創微智科&#xff09;博文大全&#xff1a;開發技術集合&#xff08;包含Qt實用技術、樹莓派、三維、O…

C++ namespace機制以及同時使用多個namespace可能存在的問題

在一個 .cpp 文件中使用了多個 using namespace 會怎么樣&#xff1f; 核心答案是&#xff1a;可能會導致“命名沖突&#xff08;Name Collision&#xff09;”和“二義性&#xff08;Ambiguity&#xff09;”&#xff0c;從而引發編譯錯誤。 當你使用 using namespace SomeNam…

基于R語言的分位數回歸技術應用

回歸是科研中最常見的統計學研究方法之一&#xff0c;在研究變量間關系方面有著極其廣泛的應用。由于其基本假設的限制&#xff0c;包括線性回歸及廣義線性回歸在內的各種常見的回歸方法都有三個重大缺陷&#xff1a;(1)對于異常值非常敏感&#xff0c;極少量的異常值可能導致結…

網絡I/O模型詳解-一次了解全部(面試經常會問到相關知識)

前言 網絡I/O模型的五種類型&#xff0c;其實在我們開發程序、設計程序、實現程序的方方面面都一直存在著&#xff0c;本文從實現原理、使用場景、優缺點、詳細的流程圖等方面進行深入的解釋&#xff0c;幫助大家更好的理解常用的五種網絡io模型&#xff0c;助力大家在工作、面…

面試150 合并K個升序鏈表

思路 對鏈表元素進行獲取&#xff0c;然后進行sort()排序&#xff0c;最后通過空節點建立鏈表法重新建立一個有序的鏈表&#xff0c;返回頭節點即可。 # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val …

BitDistiller:通過自蒸餾釋放 Sub-4-Bit 大語言模型的潛力

溫馨提示&#xff1a; 本篇文章已同步至"AI專題精講" BitDistiller&#xff1a;通過自蒸餾釋放 Sub-4-Bit 大語言模型的潛力 摘要 大語言模型&#xff08;LLMs&#xff09;的規模不斷擴大&#xff0c;在自然語言處理方面取得了令人矚目的進展&#xff0c;但這也帶來…

JavaScript 的 `querySelector` 方法詳解

querySelector 是 JavaScript 中用于選擇 DOM 元素的最強大方法之一&#xff0c;它允許你使用 CSS 選擇器語法來查找元素。 基本語法 // 返回文檔中第一個匹配指定 CSS 選擇器的元素 element document.querySelector(selectors);// 從指定元素后代中查找 element parentEle…

第九講:C++中的list與forward_list

目錄 1、list的介紹及使用 1.1、構造及賦值重載 1.2、迭代器 1.3、空間 1.4、訪問 1.5、修改 1.6、操作 2、迭代器失效 3、list的模擬實現 4、forward_list介紹與使用 4.1、構造及賦值重載 4.2、迭代器 4.3、容量 4.4、訪問 4.5、修改 4.6、操作 5、迭代器的分…

華為云數據庫 GaussDB的 nvarchar2隱式類型轉換的坑

bigint 與 nvarchar2比較時發生隱式類型轉換的坑 1. 案例分析 假設&#xff1a; table1有下面兩個字段&#xff1a;id:bigint&#xff0c; source_id nvarchar2(50)數據庫中id 的值一定大于 int4 的最大值&#xff0c;例如存在一條單據&#xff1a; id1947854462980792321&…

spring boot 集成netty,及其一些基本概念

一、基本概念 1、channel:通道&#xff0c;入站或者出站數據的載體 2、ChannelHandler&#xff1a;通道處理器&#xff0c;業務邏輯寫在這里面&#xff0c;netty 5版本將入戰和出站合并成了ChannelHandler 3、ChannelPipeline&#xff1a;通道里的管道&#xff0c;是一個或者多…

7月23日華為機考真題第一題100分

?? 點擊直達筆試專欄 ??《大廠筆試突圍》 ?? 春秋招筆試突圍在線OJ ?? bishipass.com 01. 創業投資收益優化 問題描述 K小姐剛剛大學畢業,手頭有 m m m 元資金想要進行創業投資。她發現了 k k

HTML5 跨文檔通信機制:postMessage API 詳解與應用

postMessage 是 HTML5 規范中定義的跨文檔通信&#xff08;Cross-Document Messaging&#xff09;API&#xff0c;其設計目的是解決不同源&#xff08;協議、域名、端口任一存在差異&#xff09;的窗口&#xff08;如 iframe 嵌入的文檔、window.open 創建的新窗口&#xff09;…