Java算法之排序

????????下面我們將講述七大基于比較的排序算法的基本原理及實現。并從穩定性、時間復雜度、空間復雜度3種性能對每種排序進行分析。
重點:快速排序和堆排序;難點:快速排序和歸并排序

目錄

一、排序概念

二、常見排序算法的實現

2.1 插入排序

2.1.1 直接插入排序

2.1.2 希爾排序(縮小增量排序)

2.2 選擇排序

2.2.1 直接選擇排序

2.2.2 直接選擇排序優化

2.2.3 堆排序

2.3 交換排序

2.3.1 冒泡排序

2.3.2 快速排序

1、Hoare 法

2、🔴挖坑法

3、前后指針

2.3.3 快速排序優化

1、三數取中法

2、減少遞歸深度

2.3.4 快速排序非遞歸

2.4 歸并排序

2.4.1?

2.4.2 歸并排序非遞歸實現

三、特性總結

四、其他非基于比較排序

4.1 計數排序


一、排序概念

????????穩定性:假定在待排序的記錄序列中,存在多個具有相同的關鍵字的記錄,若經過排序,這些記錄的相對次序保持 不變,即在原序列中,r[i]=r[j],且 r[i] 在 r[j] 之前,而在排序后的序列中,r[i] 仍在r[j] 之前,則稱這種排序算法是穩 定的;否則稱為不穩定的。

內部排序:數據元素全部放在內存中的排序。

外部排序:數據元素太多不能同時放在內存中,根據排序過程的要求在內外村之間移動數據的排序,例如磁盤上的排序。

二、常見排序算法的實現

2.1 插入排序

2.1.1 直接插入排序

? ? ? ? 基本思想:把待排序的記錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中,直到所有的記錄插入完為止,得到一個新的有序序列。例如玩撲克牌前對手里的牌進行整理。

比如現在你手上有一副卡牌,不看花色:10、2、9、4、7,從左往右的第2張發現比第一張小,因此將其抽出插到第一張的前面。

public class Sort {public static void insertSort(int[] array){for (int i = 1; i < array.length; i++) {int tmp = array[i];int j = i-1;for (; j >= 0; j--) {if (array[j] > tmp) {  // 若此處加了 = ,則得到的數據不穩定,但實際上直接插入排序法是穩定的array[j + 1] = array[j];}else{array[j + 1] = array[j];break;}}array[j+1] = tmp;}}
}

直接插入排序的特性:

1. 元素集合越接近有序,直接插入排序算法的時間效率越高,時間復雜度為O(N);

2. 時間復雜度:最壞情況下是 O(N2);

3. 空間復雜度:O(1),沒有開辟空間;

4. 穩定性:穩定。

2.1.2 希爾排序(縮小增量排序)

? ? ? ? 基本思想:先選定一個整數作為增量,把待排序文件中的所有數據按照這個整數為距離分成多個組,即所有距離為增量的數據分在同一組內,將每一組的數據進行排序。然后,取另一個小于原來增量的整數(可以是原來的 1/2 或者 1/3+1),重復上述的分組和排序規則,當增量 =?1時,所有數據在同一組內排好序。是直接插入排序的優化,所以直接插入排序的代碼可以直接拿來修改。如下圖

    public static void shellSort(int[] array){int gap = array.length;while (gap > 1){gap /= 2;  // 最后都能等于1shell(array, gap);}}private static void shell(int[] array, int gap) {for (int i = gap; i < array.length; i++) {int tmp = array[i];int j = i-gap;for (; j >= 0 ; j -= gap) {if (array[j] > tmp){array[j+gap] = array[j];}else{array[j+gap] = tmp;break;}}array[j+gap] = tmp;}}

希爾排序的特性:

1. 希爾排序是對直接插入排序的優化。

2. 當 gap > 1 時都是預排序,目的是讓數組更接近于有序。當 gap == 1 時,數組已經接近有序的了,這樣就會很快。這樣整體而言,可以達到優化的效果。我們實現后可以進行性能測試的對比。

3. 希爾排序的時間復雜度不好計算,因為gap的取值方法很多,導致很難去計算,因此在好些書中給出的希爾排 、序的時間復雜度都不固定,歸納總結其時間復雜度的范圍在O(n^1.3 ~ n^1.5)之間;

4、空間復雜度:O(1);

5、穩定性:不穩定。


????????性能測試:main() 方法中只有 testEfficiency() 測試數組是有序的或者無序時,各種排序方法的效率;而?testSimple() 則是查看是否排序成功。

package sort;import java.util.Arrays;
import java.util.Random;public class Test {public static void orderArray(int[] array){    // 初始化有序的數組for (int i = 0; i < array.length; i++) {// 順序array[i] = i;// 倒序//array[i] = array.length-1-i;}}public static void notOrderArray(int[] array){  // 初始化無序的數組Random random = new Random();for (int i = 0; i < array.length; i++) {array[i] = random.nextInt(10_0000);  // 生成0到10萬的隨機數}}public static void testInsertEfficiency(int[] array){array = Arrays.copyOf(array, array.length);     // 不改變原來數組的順序,而是將排序后的新的數組復制一份long startTime = System.currentTimeMillis();Sort.insertSort(array);long finishTime = System.currentTimeMillis();System.out.println("直接插入排序耗時:"+(finishTime-startTime));}public static void testShellEfficiency(int[] array){array = Arrays.copyOf(array, array.length);     // 不改變原來數組的順序,而是將排序后的新的數組復制一份long startTime = System.currentTimeMillis();Sort.shellSort(array);long finishTime = System.currentTimeMillis();System.out.println("希爾排序耗時:"+(finishTime-startTime));}public static void main(String[] args) {//testSimple();      // 測試例子給的數組testEfficiency();  // 測試耗時效率}public static void testSimple(){int[] array = {9,3,4,7,1,5,8,6,5,2};System.out.println("排序前:"+Arrays.toString(array));Sort.shellSort(array);System.out.println("排序后:"+Arrays.toString(array));}public static void testEfficiency(){int[] array = new int[10_0000];  // 數組元素個數為10萬orderArray(array);//notOrderArray(array);testInsertEfficiency(array);testShellEfficiency(array);}
}

????????對于有序的數組,直接插入排序耗時要比希爾排序短一點,但差不了多少,而如果是對無序的數組進行排序,希爾排序耗時要遠比直接插入排序耗時短,幾乎達到1:100。

2.2 選擇排序

????????基本思想:每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到全部待排序的數據元素排完 。

2.2.1 直接選擇排序

假設0下標的元素為最小值,在后面的元素中找到實際最小值,然后交換……

    public static void DirectSelectSort(int[] array){for (int i = 0; i < array.length; i++) {int minIndex = i;for (int j = i+1; j < array.length; j++) {if (array[j] < array[minIndex]){minIndex = j;}}swap(array, i, minIndex);}}private static void swap(int[] array, int i, int j) {int tmp = array[i];array[i] = array[j];array[j] = tmp;}

直接選擇排序的特性:

1. 直接選擇排序思考非常好理解,但是效率不是很好。實際中很少使用,因此重要的是算法思想;
2. 時間復雜度:O(n2),和數組是否有序無關
3. 空間復雜度:O(1)
4. 穩定性:不穩定


2.2.2 直接選擇排序優化

從左端點開始向右找到最小值將下標存到 minIndex 中,找到最大值并將下標存到 maxIndex 中。

上圖的步驟看似沒毛病,編寫代碼如下:

    public static void selectSort(int[] array){int left = 0;int right = array.length-1;while (left < right) {int minIndex = left;int maxIndex = left;for (int i = left+1; i <= right; i++) {if (array[i] > array[maxIndex]){maxIndex = i;}if (array[i] < array[minIndex]){minIndex = i;}}swap(array,left,minIndex);swap(array,right,maxIndex);left++;right--;}}

但是如果我們換一組數據進行測試,得到的結果如下:

所以在更換完最小值之后需要增加一項條件。

    public static void selectSort(int[] array){int left = 0;int right = array.length-1;while (left < right) {int minIndex = left;int maxIndex = left;for (int i = left+1; i <= right; i++) {if (array[i] > array[maxIndex]){maxIndex = i;}if (array[i] < array[minIndex]){minIndex = i;}}swap(array,left,minIndex);// 如果最大值正好是 left 下標,那么交換 left 之后,最大值給到 minIndex 下標if (maxIndex == left){maxIndex = minIndex;}swap(array,right,maxIndex);left++;right--;}}

對于無序的數組,選擇排序的耗時如下:

2.2.3 堆排序

利用堆這種數據結構來實現排序,需要注意的是升序建大根堆,降序則是建小根堆。

我的Java集合中的優先級隊列(堆)中有提及。

    public static void heapSort(int[] array){createHeap(array);  // 1、建大根堆int end = array.length-1;while (end > 0){swap(array,0,end);  // 2、交換根節點和最后一個節點的值// 3、將除了最后一個元素(已是最大值)的其他節點重新整理成大根堆siftDown(array,0,end);end--;  // 4、倒著重復上面的操作}}public static void createHeap(int[] array){int parent = (array.length-1-1)/2;for (; parent >= 0; parent--) {siftDown(array,parent,array.length);}}private static void siftDown(int[] array, int parent, int size) {int child = 2*parent+1;while (child < size){if(child+1 < size && array[child+1] > array[child]){child++;}if (array[child] > array[parent]){swap(array,child,parent);parent = child;child = 2*parent+1;}else{break;}}}

堆排序的特性:

1. 堆排序使用堆來選數,效率就高了很多;

2. 時間復雜度:O(N*log?N) ,(目前效率最快的排序方法)

3. 空間復雜度:O(1)

4. 穩定性:不穩定

2.3 交換排序

????????基本思想:所謂交換,就是根據序列中兩個記錄鍵值的比較結果來對換這兩個記錄在序列中的位置,交換排序的特點是:將鍵值較大的記錄向序列的尾部移動,鍵值較小的記錄向序列的前部移動。

2.3.1 冒泡排序

關鍵詞:趟數、循環嵌套、j+1不要越界

    public static void bubbleSort(int[] array){for (int i = 0; i < array.length-1; i++) {boolean tag = false;for (int j = 0; j < array.length-1-i; j++) {if (array[j] > array[j+1]){swap(array,j, j+1);tag = true;}}if (!tag){break;}}}

1、時間復雜度 O(N2)

????????【一般討論沒有優化情況下的時間復雜度,即沒有boolean元素和 -i 的操作】

????????【優化之后,時間復雜度可以達到 O(N)】

2、空間復雜度 O(1)

3、穩定性:穩定

2.3.2 快速排序

????????快速排序是Hoare于1962年提出的一種二叉樹結構的基于分治法的交換排序方法,其基本思想為:
任取待排序元素序列中的某元素作為基準值,按照該排序碼將待排序集合分割成兩子序列,左子序列中所有元素均小于基準值,右子序列中所有元素均大于基準值,然后最左右子序列重復該過程,直到所有元素都排列在相應位置上為止。

    public static void quickSort(int[] array){quick(array,0,array.length-1);}public static void quick(int[] array, int start, int end){if (start >= end){  // 遞歸結束條件return;}//按照基準值對數組進行分割//int pivot = partitionHoare(array,start,end);          // Hoare//int pivot = partitionDig(array,start,end);            // 挖坑//int pivot =partitionDoublePointer(array,start,end);   // 雙指針解法1int pivot = partitionDoublePointer2(array,start,end);   // 雙指針解法2// 遞歸左邊的quick(array, start, pivot-1);// 遞歸右邊的quick(array,pivot+1,end);}

????????上述為快速排序遞歸實現的主框架,與二叉樹前序遍歷規則非常像,下面的3種分割方法都是在分割之后應用上面的遞歸方法進行排序的(如下圖右側內容),因此下面只討論不同分割方法的主要思想。

1、Hoare 法

    public static void quickSort(int[] array){quick(array,0,array.length-1);}public static void quick(int[] array, int start, int end){if (start >= end){  // 遞歸結束條件return;}int pivot = partitionHoare(array,start,end);quick(array, start, pivot-1);quick(array,pivot+1,end);}private static int partitionHoare(int[] array, int left, int right){int tmp = array[left];int tmpIndex = left;while(left < right){while (left < right && array[right] >= tmp){right--;}while (left < right && array[left] <= tmp){left++;}swap(array, left, right);}swap(array,left,tmpIndex);return left;}

問題:畫圖理解 / 調試解決

????????1、為什么從后面開始找,而不是從前面開始找?

? ? ? ? 2、為什么在 while 條件中有 等于號?


快排序的特性:

1、時間復雜度:

? ? ? ??最壞情況下:當給定數據是1 2 3 4 5 6…… / ……9 8 7 6 5 4 3 2 1這種有序的情況下,是O(N2);

? ? ? ? 最好情況下:是 O(N*log?N),對于滿二叉樹來說,對上面的代碼進行優化后可實現。

2、空間復雜度:遞歸一定會開辟內存

? ? ? ? 最壞情況下: O(N),單分支二叉樹;

? ? ? ? 最好情況下: O(log?N),對于滿二叉樹,遞歸完左邊再遞歸右邊時,左邊開辟的內存會被回收。

3、穩定性:不穩定

2、🔴挖坑法

如果在題目中遇到快速排序的結果,但沒有明確指出是哪種快排時,優先考慮挖坑法。

    public static void quickSort(int[] array){quick(array,0,array.length-1);}public static void quick(int[] array, int start, int end){if (start >= end){  // 遞歸結束條件return;}int pivot = partitionDig(array,start,end);quick(array, start, pivot-1);quick(array,pivot+1,end);}private static int partitionDig(int[] array, int left, int right){int key = array[left];while(left < right){while (left < right && array[right] >= key){right--;}array[left] = array[right];while (left < right && array[left] <= key){left++;}array[right] = array[left];}array[left] = key;return left;}
3、前后指針

兩種分割的方法:


? ? ? ? 【對于有序的數組】當我們在測試快排序的效率時,程序崩潰了,這是因為遞歸需要開辟內存空間,對于十萬如此大量的且有序的數據就得開辟十萬個空間。而將數據量減小,比如1萬,并不會崩,但是效率還是比較低。

2.3.3 快速排序優化

1、三數取中法

在前面測試有序數組時程序崩潰了,這是因為遞歸有n個節點的單分支的二叉樹需要開辟n個內存,那么如果我們找到有序數組的中間值并將其作為分割的基準值,就能將有序數組分為兩部分。

    public static void quick(int[] array, int start, int end){if (start >= end){  // 遞歸結束條件return;}// 三數取中法優化,有序的數組不再是單分支的二叉樹了//System.out.println("start: " + start + " end: " + end);  // 打印也會耗時int midIndex = getMiddleIndex(array, start, end);swap(array,start,midIndex);//int pivot = partitionHoare(array,start,end);          // Hoareint pivot = partitionDig(array,start,end);            // 挖坑//int pivot =partitionDoublePointer(array,start,end);   // 雙指針解法1//int pivot = partitionDoublePointer2(array,start,end);   // 雙指針解法2quick(array, start, pivot-1);quick(array,pivot+1,end);}private static int getMiddleIndex(int[] array, int start, int end) {int mid = (start+end)/2;if (array[start] < array[end]) {if (array[mid] < array[start]) {return start;} else if (array[mid] > array[end]) {return end;} else {return mid;}} else {if (array[mid] > array[start]) {return start;} else if (array[mid] < array[end]) {return end;} else {return mid;}}}
2、減少遞歸深度

????????因為在多次的預排序后數組已經趨于有序了,所以當遞歸到小的子區間時,可以考慮使用插入排序。

比如當數據量剩下的范圍是0到7之間時,直接使用插入排序,注意修改原來編寫的插入排序的開始和結束范圍,以及使用插入排序之后及時結束進程:

    public static void quick(int[] array, int start, int end){if (start >= end){  // 遞歸結束條件return;}// 減少遞歸深度優化if (end - start <= 7){insertSortRage(array, start, end);return;    // 記得此處要結束循環了}// 三數取中法優化,有序的數組不再是單分支的二叉樹了//System.out.println("start: " + start + " end: " + end);  // 打印也會耗時int midIndex = getMiddleIndex(array, start, end);swap(array,start,midIndex);//int pivot = partitionHoare(array,start,end);          // Hoareint pivot = partitionDig(array,start,end);            // 挖坑//int pivot =partitionDoublePointer(array,start,end);   // 雙指針解法1//int pivot = partitionDoublePointer2(array,start,end);   // 雙指針解法2quick(array, start, pivot-1);quick(array,pivot+1,end);}private static void insertSortRage(int[] array, int start, int end) {for (int i = start+1; i <= end; i++) {int tmp = array[i];int j = i-1;for (; j >= start; j--){if (array[j] > tmp){array[j+1] = array[j];}else{array[j+1] = tmp;break;}}array[j+1] = tmp;}}

2.3.4 快速排序非遞歸

????????基本思想:使用一個棧來存放分割后要使用二叉樹數據結構進行排序的開始下標和結束下標。再拿出下標進行分割,就是不斷地分割、存放下標、拿出下標、分割……的過程。

    public static void quickSort(int[] array){// 非遞歸的方法quickNor(array,0,array.length-1);}private static void quickNor(int[] array, int start, int end) {Deque<Integer> stack = new ArrayDeque<>();int pivot = partitionDig(array,start,end);// 第一次分割后存放下標if (pivot > start+1){stack.push(start);stack.push(pivot-1);}if (pivot < end-1){stack.push(pivot+1);stack.push(end);}// 拿出下標再進行分割while (!stack.isEmpty()){end = stack.pop();start = stack.pop();pivot = partitionDig(array,start,end);if (pivot > start+1){stack.push(start);stack.push(pivot-1);}if (pivot < end-1){stack.push(pivot+1);stack.push(end);}}}

快速排序的特性:

1、 快速排序整體的綜合性能和使用場景都是比較好的,所以才敢叫快速排序;

2、時間復雜度:O(N*logN);

3、空間復雜度:O(logN),即樹的高度;

4. 穩定性:不穩定。

2.4 歸并排序

2.4.1?

????????基本思想:歸并排序(MERGE-SORT)是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合并成一個有序表,稱為二路歸并。 歸并排序核心步驟:

    public static void mergeSort(int[] array){mergeSortTmp(array, 0, array.length-1);}public static void mergeSortTmp(int[] array, int left, int right){if (left >= right){return;}int mid = (left + right)/2;mergeSortTmp(array, left, mid);mergeSortTmp(array, mid+1, right);// 到這里分解結束// 下面進行合并merge(array,left,mid,right);}private static void merge(int[] array, int left, int mid, int right) {int[] tmp = new int[right-left+1];int k = 0;int s1 = left;//int e1 = mid;int s2 = mid+1;//int e2 = right;while (s1 <= mid && s2 <= right){if (array[s1] < array[s2]){tmp[k++] = array[s1++];}else{tmp[k++] = array[s2++];}}while (s1 <= mid){   // 要用 while 的原因是有可能有多組tmp[k++] = array[s1++];}while (s2 <= right){tmp[k++] = array[s2++];}for (int i = 0; i < k; i++) {array[i+left] = tmp[i];  // +left處理巧妙解決右邊下標對應問題}}

歸并排序特性:

1、歸并的缺點在于需要O(N)的空間復雜度,歸并排序的思考更多的是解決在磁盤中的外部排序問題;

2、時間復雜度:O(N*log?N);

3、空間復雜度:O(N)

4、穩定性:穩定

海量數據的排序問題:

外部排序:排序過程需要在磁盤等外部存儲進行的排序

前提:內存只有 1G,需要排序的數據有 100G

????????因為內存中因為無法把所有數據全部放下,所以需要外部排序,而歸并排序是最常用的外部排序

1. 先把文件切分成 200 份,每個 512 M

2. 分別對 512 M 排序,因為內存已經可以放的下,所以任意排序方式都可以

3. 進行 2路歸并,同時對 200 份有序文件做歸并過程,最終結果就有序了

2.4.2 歸并排序非遞歸實現

????????基本思想:將數組多次分解之后合并為一整個數組進行排序。

    private static void merge(int[] array, int left, int mid, int right) {  // 合并int[] tmp = new int[right-left+1];int k = 0;int s1 = left;//int e1 = mid;int s2 = mid+1;//int e2 = right;while (s1 <= mid && s2 <= right){if (array[s1] < array[s2]){tmp[k++] = array[s1++];}else{tmp[k++] = array[s2++];}}while (s1 <= mid){   // 要用 while 的原因是有可能有多組tmp[k++] = array[s1++];}while (s2 <= right){tmp[k++] = array[s2++];}for (int i = 0; i < k; i++) {array[i+left] = tmp[i];}}// 歸并排序非遞歸public static void mergeSortNor(int[] array){int gap = 1;while (gap < array.length) {for (int i = 0; i < array.length; i = i + gap * 2) {int left = i;int mid = left + gap - 1;int right = mid + gap;merge(array, left, mid, right);  // 合并}gap *= 2;}}

上面的 mergeSortNor() 代碼看似沒有問題,但是如果是如下情況,該如何完善?

    public static void mergeSortNor(int[] array){int gap = 1;while (gap < array.length) {for (int i = 0; i < array.length; i = i + gap * 2) {int left = i;int mid = left + gap - 1;if (mid >= array.length){  // 處理越界情況mid = array.length -1;}int right = mid + gap;if (right >= array.length){right = array.length -1;}merge(array, left, mid, right);  // 合并}gap *= 2;}}

三、特性總結

堆排序、快速排序、歸并排序時間復雜度都是 O(N*log?N);但相比空間復雜度,堆排序占優勢

插入排序、冒泡排序和歸并排序都是穩定的;

排序方法最好平均最壞空間復雜度穩定性
冒泡排序O(n2)(優化之后能達到O(n))O(n2)O(n2)O(1)穩定
插入排序O(n)O(n2)O(n2)O(1)穩定

選擇排序

O(n2)O(n2)O(n2)O(1)不穩定
希爾排序O(n)O(n^1.3)O(n^1.5)O(1)不穩定
堆排序O(n * log?n)O(n * log?n)O(n * log?n)O(1)不穩定
快速排序O(n * log?n)O(n * log?n)O(n2)O(log?n)~O(n)不穩定
歸并排序O(n * log?n)O(n * log?n)O(n * log?n)O(n)穩定

一些操作關鍵詞:

四、其他非基于比較排序

4.1 計數排序

應用場景:

????????集中在某個范圍內的一組數據。

操作步驟:

????????1、新建一個計數數組來利用下標統計相同元素出現的次數;

????????2、根據統計的結果將序列回收到原來的序列中。

    public static void countSort(int[] array){// 1、找出數組中的最大值和最小值,得到申請空間的大小int max = array[0];int min = array[0];for (int i = 1; i < array.length; i++) {if (array[i] > max){max = array[i];}if (array[i] < min){min = array[i];}}int len = max - min + 1;int[] count = new int[len];// 2、遍歷數組計算出現的次數for (int i = 0; i < array.length; i++) {int index = array[i];count[index-min]++;}// 3、將計數數組中的數據按順序拿出放到 arrayint index = 0;for (int i = 0; i < count.length; i++) {while (count[i] != 0) {array[index] = i + min;index++;count[i]--;}}}

計數排序的特性:

1、計數排序在數據范圍集中時,效率很高,但是適用范圍及場景有限。

2、時間復雜度:O(MAX(N,范圍))

3、空間復雜度:O(范圍)

4、穩定性:穩定

其他:桶排序、基數排序。

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

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

相關文章

RabbitMQ:SpringAMQP 多消費者綁定同一隊列

目錄一、案例需求二、代碼實現三、總結生產者源碼 消費者源碼 一、案例需求 模擬WorkQueue&#xff0c;實現一個隊列綁定多個消費者。 在RabbitMQ的控制臺創建一個隊列&#xff0c;命名為work.queue。在生產者服務中定義測試方法&#xff0c;在1s內產生50條消息&#xff0c;…

Java技術總監的成長之路(技術干貨分享)

以下是針對 ?Java技術總監? 在 Linux 環境下搭建企業級開發環境的完整指南&#xff0c;涵蓋 JDK 配置、工程工具鏈、協作平臺及性能優化方案&#xff1a; 本文章僅提供學習&#xff0c;切勿將其用于不法手段&#xff01; 一、核心環境搭建 1. ?JDK 安裝與調優? ?版本選擇…

C++代碼解釋:實現一個 mystring 類,用于表示字符串,實現構造函數,默認構造長度為 10 的空間,提供打印字符串,獲取空間大小,修改內容的成員函數

題目代碼#include <cstring> // 包含字符串處理函數庫&#xff0c;如strlen、strncpy等 #include <iostream> // 包含輸入輸出流庫&#xff0c;用于cout等操作 using namespace std; // 使用標準命名空間&#xff0c;避免重復書寫std::class mystring { // 定…

如何解決IDEA/Datagrip無法連接數據庫的問題:解決方法為添加參數-Djava.net.preferIPv4Stack=true

如何解決IDEA/Datagrip無法連接數據庫的問題&#xff1a;解決方法為添加參數-Djava.net.preferIPv4Stacktrue 引言 在開發過程中&#xff0c;我們常常使用集成開發環境&#xff08;IDE&#xff09;如 IntelliJ IDEA 或 JetBrains DataGrip 來與數據庫進行交互。然而&#xff…

走進數字時代,融入數字生活,構建數字生態

一、準備在IT行業深耕十七年&#xff0c;始終專注于企業生產經營中的實際應用問題&#xff0c;歷經開發、測試、運維、實施、架構設計等多個技術崗位&#xff0c;并參與肉制品的生產與銷售業務&#xff0c;推進了企業主業的市場管理落地&#xff0c;積累了業務與信息技術融合的…

【Vue開發】在Vite+Vue3項目中實現離線Iconify圖標方案

在ViteVue3項目中實現離線Iconify圖標方案 項目背景 當前項目需要部署到無網絡連接的離線環境&#xff0c;因此需要將Iconify圖標集打包到項目構建結果中&#xff0c;實現完全離線使用。 技術環境 框架: Vue 3構建工具: Vite核心依賴:"iconify/json": "^2.2…

Kotlin 協程之Channel

前言 在之前的文章中&#xff0c;我們已經知道了協程的啟動、掛起、取消、異常以及常用的協程作用域等基礎應用。 這些基礎應用適合的場景是一次性任務&#xff0c;執行完就結束了的場景。 launch / async 適合的場景 網絡請求數據庫查詢文件讀寫并行計算任務等等 Channel …

linux系統裝google chrome,amd64

google chrome官網最下邊其他平臺&#xff0c;linux 查看自己的系統架構&#xff08;用下邊這行代碼查看&#xff09;&#xff0c;看看是amd還是 &#xff0c;我的顯示amd64&#xff0c;amd對應.deb,rpm對應x86 &#xff0c;選擇下載 dpkg --print-architecture 然后 sudo…

【C++基礎】C++ 中const與volatile關鍵字深度解析:從面試考點到底層實現

在 C 開發崗位的面試中&#xff0c;const與volatile關鍵字是高頻考點之一。這兩個關鍵字看似簡單&#xff0c;但實際上蘊含著豐富的語義和底層機制。本文從基礎語法到高級應用&#xff0c;結合大廠真題&#xff0c;深入解析這兩個關鍵字的奧秘。一、const關鍵字&#xff1a;常量…

達夢分布式集群DPC_故障分析_yxy

達夢分布式集群DPC_節點故障分析1 DPC核心概念回顧2 場景1-主庫故障3 場景2-少數備庫故障4 場景3-多數節點故障4.1 多數節點故障&#xff08;包括主庫&#xff09;4.2 多數備庫節點故障&#xff08;不包括主庫&#xff09;1 DPC核心概念回顧 達夢分布式集群DPC&#xff0c;基于…

【高并發內存池】一、簡介 定長內存池實現

文章目錄Ⅰ. 項目介紹1、這個項目要做什么2、項目的要求Ⅱ. 什么是內存池1、池化技術2、內存池3、mallocⅢ. 設計一個定長內存池1、定長內存池的概念2、實現如何實現定長???如何繞開 malloc 向堆直接申請空間???3、性能測試Ⅰ. 項目介紹 1、這個項目要做什么 tcmalloc源…

產品設計.原型設計

產品思維&#xff1a; 1. 產品定位&#xff1a;產品的具體的、用戶畫像&#xff1b; --什么樣的人在什么環境下做什么事情的場景 2. 范圍層: 發現、識別和決策需求。--識別真假需求&#xff0c;做ROI判斷 3. 可復用的、MVP產品方案--要能復用的解決方案&#xff0c;最小可用產品…

vue3+element-plus 輸入框el-input設置背景顏色和字體顏色,樣式效果等同于不可編輯的效果

應用效果&#xff1a;代碼&#xff1a;<template> ......<el-form-item label"文件編號" label-position"right"><el-input v-model"qualityFileForm.fileNo" clearable :disabled"!props.isNew" /></el-form-it…

[ CSS 前端 ] 網頁內容的修飾

目錄 一. CSS 1. 概述 2. 基本語法 (1)行內樣式表 (2)內嵌樣式表 (3)外部樣式表 3. 選擇器 (1)標簽選擇器: (2)類選擇器: (3)通配選擇器: (4)后代選擇器: 4. 基礎樣式 (1). 文本樣式 (2). 背景樣式 (3). 列表樣式 5. 偽類 (1)定義: (2)偽類的語法&#xff1a; …

全面深入了解榛樹游戲引擎

本文還有配套的精品資源&#xff0c;點擊獲取 簡介&#xff1a;榛樹游戲引擎&#xff08;Hazel&#xff09;是一款專為游戲開發設計的先進軟件工具&#xff0c;它集成了多種功能&#xff0c;支持現代圖形API&#xff0c;具有高性能的物理模擬系統和易學易用的腳本語言&#…

“大模型”技術專欄 | 淺談基于 Kubernetes 的 LLM 分布式推理框架架構:概覽

編者按&#xff1a;人工智能正以前所未有的滲透力重塑生產與生活圖景。作為國內領先的數據智能科技企業&#xff0c;和鯨科技自 2015 年成立以來&#xff0c;深耕人工智能與數據科學&#xff0c;歷經十年發展&#xff0c;已在氣象、教育、醫療、航空航天、金融、通信、能源、零…

【JS】認識并實現一個chrome擴展程序

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 這篇文章主要介紹chrome擴展程序。 學其所用&#xff0c;用其所學。——梁啟超 歡迎來到我的博客&#xff0c;一起學習&#xff0c;共同進步。 喜歡的朋友可以關注一下&#xff0c;下次更新不迷路&#…

jeecgboot項目遇見的一些問題:

1.當你想修改項目的標題&#xff0c;前端將jeecgboot改成你想要的標題的時候&#xff0c;去前端的.env文件中進行修改。圖1 修改標題根據路徑找到文件&#xff0c;將網站標題改成自己需要的就可以正常顯示了。圖2 顯示前圖3 顯示后2.在動態數組中&#xff0c;如果你知道數組需要…

項目里程碑設定有哪些方法

要科學設定項目里程碑&#xff0c;可采用以下幾種方法&#xff1a;基于項目階段劃分法、關鍵交付物導向法、依賴關系鏈分析法、時間驅動法、風險節點識別法、目標成果導向法、資源約束分析法、客戶驗收節點設定法。其中&#xff0c;關鍵交付物導向法尤為實用。該方法以項目中必…

英偉達顯卡驅動怎么更新 詳細步驟教程

英偉達顯卡驅動程序對于電腦的圖形性能至關重要&#xff0c;它能確保顯卡在游戲、設計、視頻渲染等方面發揮最大性能。如果驅動過舊&#xff0c;可能會導致游戲運行不暢、軟件不兼容&#xff0c;甚至系統出現錯誤。因此&#xff0c;定期更新英偉達顯卡驅動非常必要。下面將為大…