《八大排序算法》

相關概念

  • 排序:使一串記錄,按照其中某個或某些關鍵字的大小,遞增或遞減的排列起來。
  • 穩定性:它描述了在排序過程中,相等元素的相對順序是否保持不變。假設在待排序的序列中,有兩個元素a和b,它們的值相等,并且在排序前a在b前面。如果在排序后,a仍然在b前面,那么就稱該排序算法是穩定的;反之,如果排序后a跑到了b后面,那么這個排序算法就是不穩定的。
  • 內部排序:當排序的數據量非常小時,待排序的數據全部存放在計算機的內存中,并且排序操作也在內存里完成。
  • 外部排序:當待排序的數據量非常大,無法全部存入內存時,就需要借助外部存儲設備(如硬盤、磁帶等)來輔助完成排序。外部排序通常將數據分成多個較小的部分,先把這些部分依次讀入內存進行內部排序,生成有序的子文件,再把這些有序子文件合并成一個最終的有序文件。

任何排序都可以分為單趟排序和多趟排序。將排序拆解開來,更方便理解。

插入排序

直接插入排序

直接插入排序的思想是:將插入的元素按大小逐一插入到已經排序好的有序序列中,直到所有的元素都插入完成,得到一個新的有序序列。

// 打印
void PrintArr(int* a, int n)
{assert(a);for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");
}

單趟排序的思路:假設一個序列已經排序好了,現在要插入一個元素,怎么插入呢?看下面的過程。

// 單趟
// 要比較的最后一個元素的下標
int end;
// 要插入的新元素,先保存起來
int temp = a[end+1];
while(end >= 0)
{// 如果比要比較的元素小,則將這個元素后移if(tmp < a[end]){a[end+1] = a[end];// 繼續跟前一個元素比較end--;}else{break;}
}
// 走到這,1.tmp比要比較的元素大 2.比較完了,tmp比第一個元素還小,end為-1
a[end+1] = tmp;

多趟排序的思路:那么,我們就可以將亂序序列的第一個元素看做是一個已經排序好的序列,將它的后一個元素插入到這個排序好的序列中,這兩個元素就是新的排序好的序列,再將后一個元素插入到這個已經排序好的序列,依次類比。直到最后一個元素插入到已經排序好的序列中,這整個亂序序列就變成有序序列了。

void InsertSort(int* a, int n)
{assert(a);//多趟排序for (int i = 0; i < n - 1; i++) // 注意:i結束條件為最后一個元素的前一個元素下標{// 單趟// 要比較的最后一個元素的下標int end = i;// 要插入的新元素,先保存起來int tmp = a[end + 1];// 把end+1的元素插入到[0,end]while (end >= 0){// 如果比最后一個元素小,則將最后一個元素后移if (tmp < a[end]){a[end + 1] = a[end];end--;}else{break;}}// 走到這,1.tmp比要比較的元素大 2.比較完了,比第一個元素還小,end為-1a[end + 1] = tmp;}
}

我們來測試一下。

void TestInsertSort()
{int a[] = {2, 1, 4, 3, 6, 7, 0, 5, 10, 8, 9};PrintArr(a, sizeof(a) / sizeof(a[0]));InsertSort(a, sizeof(a) / sizeof(a[0]));PrintArr(a, sizeof(a) / sizeof(a[0]));
}int main()
{TestInsertSort();return 0;
}

特性總結

  1. 元素集合越接近有序,直接插入排序算法的時間效率越高。
  2. 時間復雜度:O(N^2)。
  3. 空間復雜度:O(1)。
  4. 穩定性:穩定。

希爾排序

也叫縮小增量排序。對直接插入排序的優化。直接插入排序在序列有序或接近有序的情況下效率可以達到O(N),而在逆序或接近逆序的情況下效率就是O(N^2),所以效率時好時壞。

希爾排序是如何對直接插入排序進行優化的呢?

  1. 預排序。先將數組接近有序。
  2. 直接插入排序。數組接近有序,再直接插入排序。

預排序:將間距為gap的值分為一組,分別對每個組進行插入排序。

我們先實現一組的直接插入排序。

int gap;
int end;
int tmp = a[end+gap];while(end >= 0)
{if(tmp < a[end]){a[end+gap] = a[end];end -= gap;}else{break;}
}
a[end+gap] = tmp;

其實,就相當于是插入排序,只不過插入排序gap為1。

多組是怎么排序的呢?一組一組排嗎?不是的,多組并排,非常巧妙。

int gap;
for (int i = 0; i < n - gap; i++) // i < n-gap很巧妙
{int end = i;int tmp = end + gap;while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;
}

gap越大,前面大的數據可以越快到后面,后面小的數,可以越快到前面,但是gap越大,越不接近有序。gap=1時,就是直接插入排序。

那gap設置為幾呢?希爾是這樣設計的:gap=n;gap? = n / gap + 1;只要gap大于1就是預排序,gap等于1為直接插入排序。

void ShellSort(int* a, int n)
{assert(a);int gap = n;// gap大于1預排序 ==1直接插入排序while (gap > 1){//預排序:把間距為gap的值分為一組 進行插入排序。+1保證最后是直接插入排序gap = gap / 3 + 1;//多組并排for (int i = 0; i < n - gap; i++){int end = i;int tmp = end + gap;while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}// 測試用的打印PrintArr(a, n);}
}

我們來測試一下。

void TestInsertSort()
{int a[] = {2, 1, 4, 3, 6, 7, 0, 5, 10, 8, 9};PrintArr(a, sizeof(a) / sizeof(a[0]));InsertSort(a, sizeof(a) / sizeof(a[0]));PrintArr(a, sizeof(a) / sizeof(a[0]));
}void TestShellSort()
{int a[] = { 19,30,11,20,1,2,5,7,4,8,6,26,3,29 };PrintArr(a, sizeof(a) / sizeof(a[0]));ShellSort(a, sizeof(a) / sizeof(a[0]));PrintArr(a, sizeof(a) / sizeof(a[0]));
}

下面我們來測試一下直接插入排序和希爾排序的效率。

void TestOp()
{const int N = 100000;srand(time(0));int* a1 = (int*)malloc(sizeof(int) * N);int* a2 = (int*)malloc(sizeof(int) * N);for (int i = 0; i < N; i++){a1[i] = rand();a2[i] = a1[i];}int begin1 = clock();InsertSort(a1, N);int end1 = clock();int begin2 = clock();ShellSort(a2, N);int end2 = clock();printf("InsertSort time: %d milliseconds\n", end1 - begin1);printf("ShellSort time: %d milliseconds\n", end2 - begin2);free(a1);free(a2);
}int main()
{TestOp();return 0;
}

特性總結

  1. 希爾排序是對直接插入排序的優化。
  2. 當gap>1時都是預排序,目的是讓序列接近有序。當gap==1時,數組已經接近有序了,直接插入排序,可以達到優化效果。
  3. 希爾排序的時間復雜度不好計算,因為gap的取值方法有很多。大概為O(N^1.25)~O(1.6 * N^1.25)。
  4. 穩定性:不穩定。

選擇排序

直接選擇排序

每一次都從待排序序列中找出最小元素與最大元素,放在序列的起始位置和末尾位置,直到最后所有元素排完。

void SelectSort(int* a, int n)
{assert(a);int begin = 0;int end = n-1;while (begin < end){int mini = begin; // 最小元素的下標int maxi = begin; // 最小元素的下標for (int i = begin + 1; i <= end; i++){//在[begin,end]找最小值和最大值的下標if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]){maxi = i;}}Swap(&a[begin], &a[mini]);// 如果begin和maxi的位置重疊,最大值已經被換走了,所以maxi的值需要修正if (begin == maxi){maxi = mini;}Swap(&a[end], &a[maxi]);begin++;end--;}
}

來測試一下。

void TestSelectSort()
{int a[] = { 9,1,2,5,7,4,8,6,3,5 };PrintArr(a, sizeof(a) / sizeof(a[0]));SelectSort(a, sizeof(a) / sizeof(a[0]));PrintArr(a, sizeof(a) / sizeof(a[0]));
}int main()
{TestSelectSort();return 0;
}

特性總結

  1. 效率不高。
  2. 時間復雜度:O(N^2)。
  3. 空間復雜度:O(1)。
  4. 穩定性:不穩定。

堆排序

利用堆來進行選擇排序,排升序,建大堆;排降序,建小堆。關于堆排序可以看下面這篇文章。

《二叉樹:二叉樹的順序結構->堆》

// 大堆向下調整算法 
// 注意:調整的樹的左右子樹必須為大堆
void AdjustDown(int* a, int n, int root)
{// 父親int parent = root;// 1.選出左右孩子較大的孩子跟父親比較// 默認較大的孩子為左孩子int child = parent * 2 + 1;// 終止條件孩子到葉子結點最后跟父親比一次while (child < n){// 2.如果右孩子大于左孩子,則較大的孩子為右孩子 if (child + 1 < n && a[child + 1] > a[child]){child++;}// 3.如果孩子大于父親,則跟父親交換if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapSort(int* a, int n)
{assert(a);//建堆 排升序 建大堆for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}int end = n - 1;while (end >= 1){// 交換堆頂與最后一個元素Swap(&a[0], &a[end]);// 向下調整AdjustDown(a, end, 0);end--;}
}

來測試一下。

void TestHeapSort()
{int a[] = { 9,1,2,5,7,4,8,6,3,5 };PrintArr(a, sizeof(a) / sizeof(a[0]));HeapSort(a, sizeof(a) / sizeof(a[0]));PrintArr(a, sizeof(a) / sizeof(a[0]));
}int main()
{TestHeapSort();return 0;
}

特性總結

  1. 使用堆來選數,效率高。
  2. 時間復雜度:O(NlogN)。
  3. 空間復雜度:O(1)。
  4. 穩定性:不穩定。

交換排序

根據序列中兩個鍵值的比較結果來對換這兩個記錄在序列中的位置。特點是:鍵值較大的記錄向序列的尾部移動,鍵值較小的記錄向序列的前部移動。

冒泡排序

void BubbleSort(int* a, int n)
{assert(a);int i = 0;// 整體for (int j = 0; j < n; j++){// 單趟// 判斷是否有序,如果有序,不用比較了,直接退出int flag = 0;for (i = 0; i < n-1-j; i++){if (a[i] > a[i + 1]){// 交換Swap(&a[i], &a[i + 1]);flag = 1;}}if (flag == 0){break;}}
}

來測試一下。

void TestBubbleSort()
{//int a[] = { 0,5,7,6,8,9,3,2,4,1 };//int a[] = { 0,9,1,2,3,4,5,6,7,8 };int a[] = { 9,8,7,6,5,4,3,2,1,0 };PrintArr(a, sizeof(a) / sizeof(a[0]));BubbleSort(a, sizeof(a) / sizeof(a[0]));PrintArr(a, sizeof(a) / sizeof(a[0]));
}int main()
{TestSelectSort();return 0;
}

特性總結

  1. 非常容易理解。
  2. 時間復雜度:O(N^2)。
  3. 空間復雜度:O(1)。
  4. 穩定性:穩定。

快速排序

是一種二叉樹結構的交換排序方法。取待排序元素序列中的某元素key作為基準值,按照該key,將排序集合分為兩個子序列,左子序列中所有元素都小于key,右子序列所有元素都大于key。然后左子序列和右子序列分別重復該過程,直到所有的元素都到相應的位置上。

通常取key為最右邊的值,或最左邊的值。

左右指針法

這樣,比key小的值,都換到前面了,比key大的值都換到后面了,而key在正確位置。

來看單趟排序是怎么排的。

// 單趟
int PartSort(int* a, int begin, int end)
{// key下標// 選最后一個值作為keyint keyIndex = end;while (begin < end){// 讓左邊先走// 左邊找比key大的while (begin < end && a[begin] <= a[keyIndex]) // 注意:為>=,不然會造成死循環,例如 3 5 4 7 1 2 8 5 7 5{begin++;}// 右邊再走// 右邊找比key小的while (begin < end && a[end] >= a[keyIndex]) // 注意:為>=,不然會造成死循環,例如 3 5 4 7 1 2 8 5 7 5{end--;}// 交換// 左邊的大值就交換到后邊了,右邊的小值就交換到前面了Swap(&a[begin], &a[end]);}// 走到這,代表相遇了,相遇的位置的值和key交換// 交換完之后,不管左邊和右邊是否是有序的,總之,key的位置到了正確的位置// 如果選最后一個值作為key,讓左邊先走可以保證相遇的位置的值是比key大的Swap(&a[begin], &a[keyIndex]);// 返回相遇位置return begin;
}

多趟排序,將左子序列和右子序列遞歸重復該過程即可完成整個排序。

// 多趟
void QuickSort(int* a, int left, int right)
{// 遞歸結束條件if (left >= right)return;// 此時相遇位置的值已經是正確的位置int div = PartSort(a, left, right);PrintArr(a + left, right - left + 1);// 用于打印測試的printf("[%d, %d]%d[%d, %d]\n", left, div - 1, div, div + 1, right);// 遞歸的思想,讓該位置的左邊和右邊按照同樣的思想進行排序QuickSort(a, left, div - 1);QuickSort(a, div + 1, right);
}

?來測試一下。

void TestQuickSort()
{int a[] = { 6,1,2,7,9,3,4,8,10,5 };// 如果序列本來就有序// int a[] = { 1,2,3,4,5,6,7,8,9};PrintArr(a, sizeof(a) / sizeof(a[0]));QuickSort(a, 0,sizeof(a) / sizeof(a[0])-1);PrintArr(a, sizeof(a) / sizeof(a[0]));
}int main()
{TestQuickSort();return 0;
}

可以看到遞歸的整個過程。?

再來測試一下。

void TestQuickSort()
{// int a[] = { 6,1,2,7,9,3,4,8,10,5 };// 如果序列本來就有序int a[] = { 1,2,3,4,5,6,7,8,9};PrintArr(a, sizeof(a) / sizeof(a[0]));QuickSort(a, 0,sizeof(a) / sizeof(a[0])-1);PrintArr(a, sizeof(a) / sizeof(a[0]));
}int main()
{TestQuickSort();return 0;
}

快速排序的最好情況:如果每次遞歸取key值都能取到中位數,排序的效率是最高的,因為每次都能平均將左子序列和右子序列劃分開。時間復雜度為O(NlogN)。

快速排序的最壞情況:每次遞歸取key值都是最大值或最小值,排序的效率是最差的,也就是序列在有序或接近有序的情況下,每次劃分都會產生一個空的子序列和一個長度僅比原序列少 1 的子序列。時間復雜度為O(N^2)。

那么,實際中,我們無法保證取到的key是中位數,但是,是不是可以考慮不要取到最大的或最小的。

三位數取中

三位數取中,能避免取到最大值和最小值。如果在最壞的情況有序的情況下,取序列中間的元素作為key值,與最后的元素交換,還是最右邊的值作為key值,此時就變成了最好的情況。如果是在其他,也能避免取到最大值和最小值。也就是說三位數取中,讓最壞的情況不再出現,時間復雜度綜合為O(NlogN)。

// 三位數選中
int GetMidIndex(int* a,int begin,int end)
{int midIndex = (begin + end) / 2;if (a[begin] > a[midIndex]){// begin > mid  mid > endif (a[midIndex] > a[end]){return midIndex;}// begin > mid   mid<end  else{if (a[begin] < a[end]){return begin;}else{return midIndex;}}}// begin <midelse{if (a[midIndex] < a[end]){return midIndex;}// begin<mid  mid>endelse{if (a[begin] < a[end]){return end;}else{return begin;}}}
}// 單趟
int PartSort1(int* a, int begin, int end)
{// 三位數選中 避免最壞情況int midIndex = GetMidIndex(a, begin, end);Swap(&a[midIndex], &a[end]);// key下標// 選最后一個值作為keyint keyIndex = end;while (begin < end){// 讓左邊先走// 左邊找比key大的while (begin < end && a[begin] <= a[keyIndex]) // 注意:為>=,不然會造成死循環,例如 3 5 4 7 1 2 8 5 7 5{begin++;}// 右邊再走// 右邊找比key小的while (begin < end && a[end] >= a[keyIndex]) // 注意:為>=,不然會造成死循環,例如 3 5 4 7 1 2 8 5 7 5{end--;}// 交換// 左邊的大值就交換到后邊了,右邊的小值就交換到前面了Swap(&a[begin], &a[end]);}// 走到這,代表相遇了,相遇的位置的值和key交換// 交換完之后,不管左邊和右邊是否是有序的,總之,key的位置到了正確的位置// 如果選最后一個值作為key,讓左邊先走可以保證相遇的位置的值是比key大的Swap(&a[begin], &a[keyIndex]);// 返回相遇位置return begin;
}// 多趟
void QuickSort(int* a, int left, int right)
{// 遞歸結束條件if (left >= right)return;// 此時相遇位置的值已經是正確的位置int div = PartSort1(a, left, right);// PrintArr(a + left, right - left + 1);// 用于打印測試的// printf("[%d, %d]%d[%d, %d]\n", left, div - 1, div, div + 1, right);// 遞歸的思想,讓該位置的左邊和右邊按照同樣的思想進行排序QuickSort(a, left, div - 1);QuickSort(a, div + 1, right);
}

挖坑法

取最右邊(也可以左邊的)的值作為key。該位置為坑,左邊找比key大的元素,填入到坑里,該元素的位置成為新的坑;右邊找比坑小的元素,填入到新坑里,該元素位置成為新的坑,直到相遇,將key填入到新坑。此時key的左邊就是比key小的,右邊就是比key大的。再將該key左邊的序列和右邊的序列迭代重復此操作即可。

// 單趟
int PartSort2(int* a, int begin, int end)
{assert(a);// 三位數選中 避免最壞情況int midIndex = GetMidIndex(a, begin, end);Swap(&a[midIndex], &a[end]);// 最后一個元素為坑// 坑的意思就是這的值被拿走了,可以覆蓋新的值int key = a[end];while (begin < end){// begin找大的放進坑 begin成為新坑while (begin < end && a[begin] <= key){begin++;}a[end] = a[begin];// end找小的放進新坑 end成為新坑while (begin < end && a[end] >= key){end--;}a[begin] = a[end];}//把最后一個元素放到相遇位置a[begin] = key;return begin;
}
// 多趟
void QuickSort(int* a, int left, int right)
{// 遞歸結束條件if (left >= right)return;// 此時相遇位置的值已經是正確的位置// 左右指針法// int div = PartSort1(a, left, right);// 挖坑法int div = PartSort2(a, left, right);// PrintArr(a + left, right - left + 1);// 用于打印測試的// printf("[%d, %d]%d[%d, %d]\n", left, div - 1, div, div + 1, right);// 遞歸的思想,讓該位置的左邊和右邊按照同樣的思想進行排序QuickSort(a, left, div - 1);QuickSort(a, div + 1, right);
}

前后指針法?

// 單趟
int PartSort3(int* a, int begin, int end)
{assert(a);//三位數選中 避免最壞情況int midIndex = GetMidIndex(a, begin, end);Swap(&a[midIndex], &a[end]);int keyIndex = end;int prev = begin - 1;int cur = begin;while (cur < end){if (a[cur] < a[keyIndex] && ++prev != a[cur]) // ++prev如果和cur相等 自己跟自己交換不用交換{//交換Swap(&a[prev], &a[cur]);}cur++;}Swap(&a[++prev], &a[keyIndex]);return prev;
}
// 多趟
void QuickSort(int* a, int left, int right)
{// 遞歸結束條件if (left >= right)return;// 此時相遇位置的值已經是正確的位置// 左右指針法// int div = PartSort1(a, left, right);// 挖坑法// int div = PartSort2(a, left, right);// 前后指針法int div = PartSort3(a, left, right);// PrintArr(a + left, right - left + 1);// 用于打印測試的// printf("[%d, %d]%d[%d, %d]\n", left, div - 1, div, div + 1, right);// 遞歸的思想,讓該位置的左邊和右邊按照同樣的思想進行排序QuickSort(a, left, div - 1);QuickSort(a, div + 1, right);
}

快速排序就像一顆二叉樹一樣,選出一個key分出左區間和右區間,左區間的值都比key小,右區間的值都比key大,再再左區間中找出一個key分出左區間和右區間,在右區間中找出一個key分出左區間和右區間......

快速排序還有可以優化的地方,當不斷的遞歸劃分區間,區間已經數據很少時,不用再遞歸方式劃分區間排序了,使用插入排序去排序,減少整體的遞歸次數。

// 多趟
void QuickSort(int* a, int left, int right)
{// 遞歸結束條件if (left >= right)return;// 此時相遇位置的值已經是正確的位置// 左右指針法// int div = PartSort1(a, left, right);// 挖坑法// int div = PartSort2(a, left, right);// 前后指針法int div = PartSort3(a, left, right);// PrintArr(a + left, right - left + 1);// 用于打印測試的// printf("[%d, %d]%d[%d, %d]\n", left, div - 1, div, div + 1, right);// 區間大于十個元素用快速排序if ((right - left + 1) > 10){int div = PartSort3(a, left, right);// 遞歸的思想,讓該位置的左邊和右邊按照同樣的思想進行排序QuickSort(a, left, div - 1);QuickSort(a, div + 1, right);}// 小于十個元素用插入排序else{InsertSort(a + left, right - left + 1);}
}

特性總結

  1. 快速排序整體的綜合性能和使用場景都是比較好的,所以才敢叫快速排序。
  2. 時間復雜度:O(NlogN)。
  3. 空間復雜度:O(1),使用棧模擬則為O(logN)。
  4. 穩定性:不穩定。

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

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

相關文章

深度學習篇---paddleocr正則化提取

文章目錄 前言一、代碼總述&介紹1.1導入必要的庫1.1.1cv21.1.2re1.1.3paddleocr 1.2初始化PaddleOCR1.3打開攝像頭1.4使用 PaddleOCR 進行識別1.5定義正則表達式模式1.6打印提取結果1.7異常處理 二、正則表達式2.1簡介2.2常用正則表達式模式及原理2.2.1. 快遞單號模式2.2.2…

JavaScript DOM與元素操作

目錄 DOM 樹、DOM 對象、元素操作 一、DOM 樹與 DOM 對象 二、獲取 DOM 元素 1. 基礎方法 2. 現代方法&#xff08;ES6&#xff09; 三、修改元素內容 四、修改元素常見屬性 1. 標準屬性 2. 通用方法 五、通過 style 修改樣式 六、通過類名修改樣式 1. className 屬…

單元測試的編寫

Python 單元測試示例 在 Python 中&#xff0c;通常使用 unittest 模塊來編寫單元測試。以下是一個簡單的示例&#xff1a; 示例代碼&#xff1a;calculator.py # calculator.py def add(a, b):return a bdef subtract(a, b):return a - b 單元測試代碼&#xff1a;test_c…

大模型學習:從零到一實現一個BERT微調

目錄 一、準備階段 1.導入模塊 2.指定使用的是GPU還是CPU 3.加載數據集 二、對數據添加詞元和分詞 1.根據BERT的預訓練&#xff0c;我們要將一個句子的句頭添加[CLS]句尾添加[SEP] 2.激活BERT詞元分析器 3.填充句子為固定長度 代碼解釋&#xff1a; 三、數據處理 1.…

10組時尚復古美學自然冷色調肖像電影照片調色Lightroom預設 De La Mer – Nautical Lightroom Presets

De La Mer 預設系列包含 10 種真實的調色預設&#xff0c;適用于肖像、時尚和美術。為您的肖像攝影帶來電影美學和個性&#xff01; De La Mer 預設非常適合專業人士和業余愛好者&#xff0c;可在桌面或移動設備上使用&#xff0c;為您的攝影項目提供輕松的工作流程。這套包括…

SDL多窗口多線程渲染技術解析

SDL多窗口多線程渲染技術解析 技術原理 SDL多線程模型與窗口管理 SDL通過SDL_Thread結構體實現跨平臺線程管理。在多窗口場景中,每個窗口需關聯獨立的渲染器,且建議遵循以下原則: 窗口與渲染器綁定:每個窗口創建時生成專屬渲染器(SDL_CreateRenderer),避免跨線程操作…

QT 跨平臺發布指南

一、Windows 平臺發布 1. 使用 windeployqt 工具 windeployqt --release --no-compiler-runtime your_app.exe 2. 需要包含的文件 應用程序 .exe 文件 Qt5Core.dll, Qt5Gui.dll, Qt5Widgets.dll 等 Qt 庫 platforms/qwindows.dll 插件 styles/qwindowsvistastyle.dll (如果使…

L2-037 包裝機 (分數25)(詳解)

題目鏈接——L2-037 包裝機 問題分析 這個題目就是模擬了物品在傳送帶和筐之間的傳送過程。傳送帶用隊列模擬&#xff0c;筐用棧模擬。 輸入 3 4 4 GPLT PATA OMSA 3 2 3 0 1 2 0 2 2 0 -1輸出 根據上述操作&#xff0c;輸出的物品順序是&#xff1a; MATA樣例分析 初始…

機器學習的一百個概念(4)下采樣

前言 本文隸屬于專欄《機器學習的一百個概念》&#xff0c;該專欄為筆者原創&#xff0c;引用請注明來源&#xff0c;不足和錯誤之處請在評論區幫忙指出&#xff0c;謝謝&#xff01; 本專欄目錄結構和參考文獻請見[《機器學習的一百個概念》 ima 知識庫 知識庫廣場搜索&…

qt6下配置qopengl

qt部件選擇 Qt 6&#xff1a;需要手動選擇 Qt Shader Tools 和 Qt 5 Compatibility Module&#xff08;如果需要兼容舊代碼&#xff09; cmake文件 cmake_minimum_required(VERSION 3.16) # Qt6 推薦最低 CMake 3.16 project(myself VERSION 0.1 LANGUAGES CXX)set(CMAKE_A…

數據安全系列4:密碼技術的應用-接口調用的身份識別

傳送門 數據安全系列1&#xff1a;開篇 數據安全系列2&#xff1a;單向散列函數概念 數據安全系列3&#xff1a;密碼技術概述 什么是認證&#xff1f; 一談到認證&#xff0c;多數人的反應可能就是"用戶認證" 。就是應用系統如何識別用戶的身份&#xff0c;直接…

STL之map和set

1. 關聯式容器 vector、list、deque、 forward_list(C11)等&#xff0c;這些容器統稱為序列式容器&#xff0c;因為其底層為線性序列的數據結構&#xff0c;里面存儲的是元素本身。 關聯式容器也是用來存儲數據的&#xff0c;與序列式容器不同的是&#xff0c;其里面存儲的是結…

Vue3 其它API Teleport 傳送門

Vue3 其它API Teleport 傳送門 在定義一個模態框時&#xff0c;父組件的filter屬性會影響子組件的position屬性&#xff0c;導致模態框定位錯誤使用Teleport解決這個問題把模態框代碼傳送到body標簽下

C++練習

1.將File練習題&#xff0c;內部的FILE*描述符&#xff0c;改成int描述符 2。寫一個類Fifo管道類。提高難度&#xff0c;什么都不提示。只要求&#xff1a;使用自己編寫的Fifo類對象&#xff0c;實現2個終端之間互相聊天 file.cpp #include <iostream> #include <c…

《Python Web網站部署應知應會》No4:基于Flask的調用AI大模型的高性能博客網站的設計思路和實戰(上)

基于Flask的調用AI大模型的高性能博客網站的設計思路和實戰&#xff08;上&#xff09; 摘要 本文詳細探討了一個基于Flask框架的高性能博客系統的設計與實現&#xff0c;該系統集成了本地AI大模型生成內容的功能。我們重點關注如何在高并發、高負載狀態下保持系統的高性能和…

實現一個簡易版的前端監控 SDK

【簡易版的前端監控系統】 1、Promise的錯誤如何監控&#xff1f;–promise不是所有都是接口請求 2、接口的報錯如何監控&#xff1f;–全局監控sdk&#xff0c;不改動公共的請求方法、不改動業務代碼&#xff1b;一般接口使用axios請求 3、資源的報錯如何監控&#xff1f; 4、…

【操作系統】軟中斷vs硬中斷

在操作系統中&#xff0c;中斷&#xff08;Interrupt&#xff09; 是 CPU 響應外部事件的重要機制&#xff0c;分為 硬中斷&#xff08;Hardware Interrupt&#xff09; 和 軟中斷&#xff08;Software Interrupt&#xff09;。它們的核心區別在于 觸發方式 和 處理機制。 1. 硬…

力扣刷題-熱題100題-第27題(c++、python)

21. 合并兩個有序鏈表 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/merge-two-sorted-lists/description/?envTypestudy-plan-v2&envIdtop-100-liked 常規法 創建一個新鏈表&#xff0c;遍歷list1與list2&#xff0c;將新鏈表指向list1與list2…

Python包下載路徑 Chrome用戶數據 修改到非C盤

查看 site-packages 是否能通過命令行完成&#xff1f; 可以&#xff0c;使用以下命令&#xff08;不需寫腳本&#xff09;&#xff1a; python -m site輸出包含&#xff1a; sys.path site-packages 路徑&#xff08;全局和用戶級&#xff09; 如果只想看安裝路徑&#…

【鴻蒙5.0】鴻蒙登錄界面 web嵌入(隱私頁面加載)

在鴻蒙應用中嵌入 Web 頁面并加載隱私頁面&#xff0c;可借助 WebView 組件來實現。以下是一個完整示例&#xff0c;展示如何在鴻蒙 ArkTS 里嵌入 Web 頁面并加載隱私政策頁面。 在 HarmonyOS 應用開發中&#xff0c;如果你希望嵌入一個網頁&#xff0c;并且特別關注隱私頁面加…