您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

排序算法详解(java代码实现)

时间:2022-06-08 11:18:39  来源:  作者:java研习社

排序算法大致分为内部排序和外部排序两种

内部排序:待排序的记录全部放到内存中进行排序,时间复杂度也就等于比较的次数

外部排序:数据量很大,内存无法容纳,需要对外存进行访问再排序,把若干段数据一次读入内存使用内部排序的方法进行排序后写入外存,再将这若干个已经排序的数据进行归并,时间复杂度等于IO(访问外存)的次数

排序算法详解(java代码实现)

 

1、冒泡算法

交换排序。属于比较简单直观的排序算法,以升序为例(从小到大),每次比较相邻的两个元素,如果左侧元素比右侧的大,则交换两个元素的位置,每次把循环中最大的元素放在循环的最后,像冒泡一样从小到最大。

1.1 算法步骤

  1. 比较 a[j] 和 a[j+1],如果 a[j] > a[j+1],swap交换两个元素在数组中的位置
  2. 让每一对相邻元素进行以上的比较,直到把最大的值放到比较的数组最后
  3. 重复以上步骤n-1次

1.2 时间复杂度

​ 总共需要比较次数(n为数组元素个数 n >= 1):

[O(n)=(n-1)+(n-2)+cdots+1=frac{(n-1)*n}{2}\ 取最高次幂O(n)=n^2 ]
 

1.3 代码实现

public int[] bubbleSort(int[] arr) {
 // 外层循环,数组长度为 n,循环次数为 n-1
 for (int i = 0; i < arr.length - 1; i++) {
  // 内层循环,循环次数为 n-1-i,找到一个最大值放在,arr[n-1-i]的位置
  for (int j = 0; j < arr.length - 1 - i; j++) {
   // 比较相邻的两个值,把相对大的值放在数组下标大的地方
   if (arr[j] > arr[j + 1]) {
    // swap交换
    int temp = arr[j];
    arr[j] = arr[j + 1];
    arr[j + 1] = temp;
   }
  }
 }
 return arr;
}

1.4 图示

​ 如图,即使第二次循环已经排好序,但是程序不晓得,仍会继续循环进行排序,最后一次,只有两个元素进行排序比较,直接排序完成,排序次数 n-1。

排序算法详解(java代码实现)

 


排序算法详解(java代码实现)

 

2、快速排序

​ 交换排序。选择一个基准值,将数组划分两个区域,左侧的值全部比右侧的值小,然后分别对两个区域继续进行区域的划分与排序,直到排序完成。

2.1 算法步骤

  1. 从数组中按照一定的规则选择一个元素作为基准值
  2. 把基准值与其他元素进行比较,将元素分成两部分,把所有比基准值小的值放在左侧,所有比基准值大的放在右侧。即进行区域划分
  3. 通过递归上述操作,再次将左右两区域进行区域划分,完成排序

2.2 时间复杂度

​ 对区域划分取特殊值,假设n为2的幂,每次都将n个数平均划分,所以第一次对一整个区域进行循环n次划分2个区域,第二次对两个区域分别进行循环(frac{n}{2})次,共n次,划分4个区域,第三次对4个区域分别进行循环(frac{n}{4})次,共计n次,以此类推,最后一次为第log2n次,划分的每个区域仅有一个元素。即:

[O(n)=n*log_2n ]
 

2.3 代码实现

private static int[] quickSort(int[] arr, int left, int right) {
 if (left < right) {
  int partitionIndex = partition(arr, left, right);
  // 左侧右侧区间再分别进行排序
  quickSort(arr, left, partitionIndex - 1);
  quickSort(arr, partitionIndex + 1, right);
 }
 return arr;
}

// 以基准值将数组arr的left~right区间进行分区,保证返回的下标左侧元素比基准值小,右侧比基准值大
private static int partition(int[] arr, int left, int right) {
 // 设定基准值为最左侧元素,本身不参与循环中的交换,仅在最后放到index的位置
 int pivot = left;
 // 该index用于标记一个下标,代表当前已经遍历的元素中,index位置的元素是最后一个比基准值小的元素
 // arr[index]本身以及数组左侧元素都小于基准值
 int index = left;
 // 遍历left+1~right区间(因为基准值自身不需要进行比较交换)
 for (int i = left+1; i <= right; i++) {
  if (arr[i] < arr[pivot]) {
   // 保证从当前遍历到的最后一个比基准值小的元素的下一个元素开始交换,所以先++再交换
   index++;
   swap(arr, i, index);
  }
 }
 // 此时index为分界点,arr[index]<arr[index+1]
 // 其他元素交换完毕之后arr[index]的值应该为基准值,所以进行元素位置交换
 swap(arr, pivot, index);
 // 此时arr[index]两侧元素左小右大
 return index;
}
// 元素交换
private static void swap(int[] arr, int i, int j) {
 int temp = arr[i];
 arr[i] = arr[j];
 arr[j] = temp;
}

2.4 图示

排序算法详解(java代码实现)

 


排序算法详解(java代码实现)

 

3、直接插入排序

​ 插入排序。每一次把一个待排序的记录,按照值的大小,插入到有序数组的合适位置。

​ 相当于把a[n]分割,先排序数组 a[0] ~ a[1],再 a[0] ~ a[2],直到 a[0] ~ a[n] 全部排序完成。

3.1 算法步骤

  1. 第一个元素之前没有值,认为已经排序
  2. 取下一个待排序元素,下标为 i,向前进行比较
  3. 如果待排序元素比待比较元素小,则交换位置
  4. 重复步骤3直到有一个元素等于或者小于待排序元素,此次内循环结束,a[0] ~ a[i]排序完成
  5. 重复步骤2~4,直到最后一个元素

3.2 时间复杂度

​ 认为第一元素已经排好序,从第二个元素开始向前比较,计算需要比较的次数:

[O(n) = 1+2+3+cdots+n-1= frac{(n-1)*n}{2}\ 即O(n) = n^2 ]
 

3.3 代码实现

public static int[] insertionSort(int[] arr){
 // 从第二个元素开始到最后一个元素
 for (int i = 1; i < arr.length; i++) {
  // 向前遍历
  for( int j = i ; j > 0 ; j -- ){
   if( arr[j] < arr[j-1] ){
    	swap( arr, j , j-1 ); 
   } 
   else{
    break;
   }  
  }
 }
 return arr;
}
private static void swap(int[] arr, int i, int j) {
 int temp = arr[i];
 arr[i] = arr[j];
 arr[j] = temp;
}

3.4 图示

排序算法详解(java代码实现)

 


排序算法详解(java代码实现)

 

4、希尔排序

​ 插入排序。因为设计该算法的人叫Shell,所以叫希尔排序,又称缩小增量排序。思路上是将待排序序列分割成若干个子序列进行直接插入排序,并逐渐缩减少子序列个数,直到针对整体进行一次排序。

4.1 算法步骤

  1. 设置一个递减增量序列 $$t_1,t_2,cdots,t_k$$,(t_k)为1
  2. 按照增量个数k,整体上对序列进行k次排序
  3. 每次排序,根据增量 t,将序列分割成 (数组长度 / (t_i)) 个子序列,对子序列分别进行直接插入排序,当增量为1时,对序列整体进行一次排序

4.2 时间复杂度

​ 希尔排序的时间复杂度和增量的选择有关,证明的话我是不会,最坏时间复杂度是(O(n^2)),当n在某个范围内时,可以达到(O(n^{1.3}))

4.3 代码实现

/**
	该代码与实际算法步骤有区别:
	算法步骤是说针对每个子序列进行直接插入排序,实际上对每个子序列的直插排序是交替进行的
**/
public static void shellSort(int[] arr) {
 int length = arr.length;
 // 记录需要进行直接插入排序的值
 int temp;
 // 增量step从length/2递减到1进行循环
 for (int step = length / 2; step >= 1; step /= 2) {
  // 进行直插排序,默认第一个元素已经排序完成,从step下标的元素开始向前进行直插
  for (int i = step; i < length; i++) {
   // 需要对arr[i]进行直接插入排序,记录该值
   temp = arr[i];
   // j来记录temp最后需要插入的位置
   int j = i;
   while (j -step >= 0 && arr[j-step] > temp) {
    arr[j] = arr[j-step];
    j -= step;
   }
   arr[j] = temp;
  }
 }
}

// 使用直接插入版本的代码:
private static void shellSort2(int[] arr) {
 int len = arr.length;
 for (int step = len / 2; step > 0; step = step / 2) {
  // 直接插入排序的代码,只不过向前遍历时遍历的数组为i,i-step,i-step-step...
  for (int i = step; i < arr.length; i++) {
   for (int j = i; j-step >= 0; j -= step) {
    if (arr[j] < arr[j - step]) {
     swap(arr, j, j - step);
    }
   }
  }
 }
}
private static void swap(int[] arr, int i, int j) {
  int temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

4.4 图示

排序算法详解(java代码实现)

 


排序算法详解(java代码实现)

 

5、简单选择排序

​ 选择排序。从未排序序列中查找一个最小值,然后将该值放到已排序序列的末尾位置,循环下去,直到最后一个元素。

5.1 算法步骤

  1. 从 a[i] 开始,i=0,1,2,...,n,在数组中找到最小值的下标,放到arr[i],此时 a[0] ~ a[i] 有序,a[i+1] ~ a[n] 待排序
  2. 待排序序列重复步骤1
  3. 经过n-1次循环完成排序

5.2 时间复杂度

​ 循环次数为n-1,n-2,n-3,(cdots),1

[O(n) = (n-1)+(n-2)+cdots+1\ O(n) = frac{1}{2}(n^2-n)\ O(n) = n^2 ]
 

5.3 代码实现

public static int[] selectionSort(int[] arr){
 // 外层循环经过 n-1 轮比较
 for (int i = 0; i < arr.length - 1; i++) {
  // min用来记录每次比较过程中最小值的下标
  int min = i;
  // 0~i已经排序完成,从i向后比较查找后面序列的最小值
  for (int j = i + 1; j < arr.length; j++) {
   if (arr[j] < arr[min]) {
    // 记录最小值元下标
    min = j;
   }
  }
  // 将找到的最小值和i位置所在的值进行交换
  if (i != min) {
   swap(arr, i ,min);
  }
 }
 return arr;
}

5.4 图示

排序算法详解(java代码实现)

 


排序算法详解(java代码实现)

 

6、堆排序

​ 选择排序。将待排序列构造诚大根堆,根节点则为序列中最大元素,将该节点与最后一个值交换,把剩余的节点重新构建大根堆,继续进行交换,直到待排序列只剩下一个值。

​ 大根堆(大顶堆):父节点一定大于两个子节点的值,即:arr[i] > arr[2i+1] && arr[i] > arr[2i+2]

​ 将大根堆映射到数组中示例:

6.1 算法步骤

  1. 将待排序数组构建成大根堆(仍然是无序的),根节点则为数组最大值
  2. 将根节点和最后一个节点进行交换,则最大值放到了数组尾部,此时 a[0] ~ a[n-1] 无序
  3. 因为步骤2进行了节点交换,需要对 a[0] ~ a[n-1] 重新构建大根堆
  4. 重复步骤 2,3 直到全部有序

6.2 时间复杂度

  1. 初始化大根堆

​ 设元素个数为 n,建堆的高度 (k=log_2(n+1)),

​ 第 i 层的非叶子节点的最大操作(交换)次数为 k-i

​ 第 i 层的节点个数为 (2^{i-1})

​ 所以第 i 层总共需要操作 ((k-i)(2^{i-1})) 次,总共需要操作的次数为

[S = (k-1)*2^0 + (k-2)*2^{1}+(k-3)*2^2+cdots+(k-(k-1))*2^{k-1-1} ]
 

​ 用 2S - S计算 S 的值:

[S = 2^1+2^2+cdots+2^{k-1}-(k-1)\ S = 2^k-k-1 ]
 

​ 将 (k=log_2{(n+1)}Approx log_2n) 代入得

[O(n) = n - log_2n-1 \取最高项O(n) = n ]
 

​ 则初始化大根堆的时间复杂度 O(n) = n

2.重新调整堆

​ 根节点和待排序数组的最后一个元素 a[i] 交换之后,需要重新调整堆,最大调整次数 = a[i] 所在堆的层数 = (log_2i),总共需要调整的次数 = ((n-1)(log_2n)) ,所以调整堆的时间复杂度为

[O(n) = nlog_2n ]
 

总的时间复杂度 (O(n) = n + nlog_2n = nlog_2n)

6.3 代码实现

public static int[] HeapSort(int[] arr) {
 int len = arr.length;
 // 对所有元素建立大根堆
 buildMaxHeap(arr, len);
 // 从数组尾开始进行循环,每次找到待排序序列的最大值
 for (int i = arr.length - 1; i > 0; i--) {
  // 此时arr[0]为最大值,交换根节点arr[0]和最后一个节点 i
  swap(arr, 0, i);
  len--;
  // 剩余元素重新建堆
  heapify(arr, 0, len);
 }
 return arr;
}
private static void buildMaxHeap(int[] arr, int len) {
 for (int i = len / 2; i >= 0; i--) {
  heapify(arr, i, len);
 }
}
/**
 * @param arr  排序数组
 * @param parent 父节点下标
 * @param len  待排序数组 length
 */
private static void heapify(int[] arr, int parent, int len) {
 // 计算父节点的两个子节点下标
 int left = 2 * parent + 1;
 int right = 2 * parent + 2;
 // largest为父节点和子节点最大值的下标
 int largest = parent;
 // 比较左右子节点和父节点的大小
 if (left < len && arr[left] > arr[largest]) {
  largest = left;
 }
 if (right < len && arr[right] > arr[largest]) {
  largest = right;
 }
 // 如果当前的最大值不是当前父节点,需要进行元素交换,
 // 交换之后的子节点作为父节点时不一定是大根堆,需要重新建堆
 if (largest != parent) {
  swap(arr, parent, largest);
  heapify(arr, largest, len);
 }
}
private static void swap(int[] arr, int i, int j) {
 int temp = arr[i];
 arr[i] = arr[j];
 arr[j] = temp;
}

6.4 图示

初始化大根堆:

排序算法详解(java代码实现)

 

循环取堆顶元素排序:建议自己画二叉树更明晰

排序算法详解(java代码实现)

 

完整动图:

排序算法详解(java代码实现)

 

7、归并排序

​ 将两个及以上的有序表合并成一个有序表。以下为两路合并排序。

​ 采用分治法,把无序数组两两分割,分割数次,然后自下至上将两个子序列进行排序,然后合并成一个有序数组,逐渐向上进行两两合并,直到合并成一个有序数组。

7.1 算法步骤

  1. 将数组从中间拆分为两个无序数组
  2. 通过递归继续执行步骤 1
  3. 通过两个指针指向两个数组的起始位置
  4. 比较指针指向的两个元素,把较小的放入合并数组,移动指针向后
  5. 重复步骤4直到某一个指针到达数组尾部,此时另一个数组的元素全部不小于合并数组元素
  6. 将另一个数组的元素放入合并数组
  7. 继续归并,直到剩下一个数组

7.2 时间复杂度

​ 时间复杂度 = 两个数组归并排序的时间复杂度 + 重建大根堆的时间复杂度

​ $f(n) = 2f(frac{n}{2})+ n $

​ (n = frac{n}{2}) : : (f(frac{n}{2}) = 2f(frac{n}{4}) + frac{n}{4})

​ (n=frac{n}{4}) : : (f(frac{n}{4})=2f(frac{n}{8}) + frac{n}{8})

​ (cdots)

​ (n=frac{n}{2^{m-1}}) : : (f(frac{n}{2^{m-1}}) = 2f(frac{n}{2^m}) + frac{n}{2^{m-1}})

​ 即:(f(n) = 2f(frac{n}{2}) + n)

​ (=2[2f(frac{n}{4} + frac{n}{4}) + n]) = $ 22f(frac{n}{22}) + 2n$

​ (=2^2[f(2f(frac{n}{8}) + frac{n}{4})] + 2n) = (2^3f(frac{n}{2^3}) + 3n)

​ (cdots)

​ (=2^mf(frac{n}{2^m}) + mn)

​ 当数组被分割成仅剩一个元素时,此时分割为(2^mf(1)+mn) 即: (frac{n}{2^m} = 1)

​ 则:(m = log_2n)

​ 代入得(f(n) = 2^{log_2n}f(1) + n * log_2n = n + nlog_2n)

​ 所以归并排序的时间复杂度为:

[O(n) = nlog_2n ]
 

7.3 代码实现

public static int[] MergeSort(int[] arr) {
 // 数组中仅有一个元素==已排序
 if (arr.length < 2) {
  return arr;
 }
 // 分割数组的下标
 int middle = arr.length / 2;
 // 将数组分割成arr[0] ~ arr[middle-1] 和 arr[middle] ~ arr[length-1] 两部分
 int[] left = Arrays.copyOfRange(arr, 0, middle);
 int[] right = Arrays.copyOfRange(arr, middle, arr.length);
 /**
  * 可以拆分为
  * int[] arr1 = MergeSort(left);
  * int[] arr2 = MergeSort(right);
  * 对两个分割后的数组分别再进行归并排序
  * return merge(arr1, arr2);
  */
 return merge2(MergeSort(left), MergeSort(right));
}
/**
 * 将两个数组进行合并方法 1
 */
protected static int[] merge1(int[] left, int[] right) {
 // 合并后的数组
 int[] result = new int[left.length + right.length];
 // i 进行计数,直到等于left或者right数组的长度
 int i = 0;
 // 循环对left和right数组的首个元素进行比较,把小的放入result数组
 // 并重新给left或right数组赋值
 while (left.length > 0 && right.length > 0) {
  if (left[0] <= right[0]) {
   result[i] = left[0];
   left = Arrays.copyOfRange(left, 1, left.length);
  } else {
   result[i] = right[0];
   right = Arrays.copyOfRange(right, 1, right.length);
  }
  i++;
 }
 // 此时left或right数组有一个已经遍历完毕,直接把剩下的元素全部放入result数组
 while (left.length > 0) {
  result[i] = left[0];
  i++;
  left = Arrays.copyOfRange(left, 1, left.length);
 }
 while (right.length > 0) {
  result[i] = right[0];
  i++;
  right = Arrays.copyOfRange(right, 1, right.length);
 }
 return result;
}
/**
 * 将两个数组进行合并方法 2
 * 个人还是倾向于这个直观的
 */
private static int[] merge2(int[] left, int[] right) {
 // 合并后的结果
 int[] result = new int[left.length + right.length];
 // i,j分别用于遍历left,right数组
 int i = 0;
 int j = 0;
 // count用于放入result数组时的下标计数
 int count = 0;
 // 循环对left和right数组元素进行比较,并把小的赋值给result[count]
 // 直到遍历完left或者right数组
 while (i < left.length && j < right.length) {
  if (left[i] < right[j]) {
   result[count] = left[i];
   i++;
  } else {
   result[count] = right[j];
   j++;
  }
  count++;
 }
 // 此时left或right数组有一个已经遍历完毕,直接把剩下的元素全部放入result数组
 while (i < left.length) {
  result[count] = left[i];
  i++;
  count++;
 }
 while (j < right.length) {
  result[count] = right[j];
  j++;
  count++;
 }
 return result;
}

7.4 图示

注:两个图不是同一个算法过程

排序算法详解(java代码实现)

 


排序算法详解(java代码实现)

 

8、基数排序

​ 取得最大整数的位数,从个位开始进行比较放入新的数组,再收集起来,此时数组按照个位有序排列,再进位进行比较收集,以此类推,直到最高位比较完成,此时数组全部有序。

8.1 算法步骤

  1. 取得数组最大数的位数
  2. 根据数组元素个位数的大小放入不同的数组中
  3. 按照顺序将数组中的元素收集起来,此时新的数组按数组元素的个位数有序
  4. 数组元素进位(十位、百位...)按照该位的大小重复2、3
  5. 直到按照最大位数进行元素收集后所有元素有序

8.2 时间复杂度

​ 设n个数的最大值是k位数,需要的桶(收集元素的数组)为r个,进行一次遍历元素收集的时间复杂度为O(n+r),总的时间复杂度就是O(k(n+r)),一般来说,n >> r 且 n >> k,所以可以认为基数排序的时间复杂度为O(n),也可以认为事件复杂度为O(kn)。

8.3 代码实现

private static int[] RadixSort(int[] arr, int maxDigit) {
 int mod = 10;
 int dev = 1;
 for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
  // 使用二维数组作为桶存放数据
  // 考虑负数的情况,其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10)
  int[][] counter = new int[mod * 2][0];
  for (int j = 0; j < arr.length; j++) {
   int bucket = ((arr[j] % mod) / dev) + mod;
   counter[bucket] = arrayAppend(counter[bucket], arr[j]);
  }
  // 收集数组中的数据
  int pos = 0;
  for (int[] bucket : counter) {
   for (int value : bucket) {
    arr[pos++] = value;
   }
  }
 }
 return arr;
}
// 自动扩容,并保存数据
private static int[] arrayAppend(int[] arr, int value) {
 arr = Arrays.copyOf(arr, arr.length + 1);
 arr[arr.length - 1] = value;
 return arr;
}
// 获取最高位数
private static int getMaxDigit(int[] arr) {
 int maxValue = getMaxValue(arr);
 return getNumLength(maxValue);
}
// 获取最大值
private static int getMaxValue(int[] arr) {
 int maxValue = arr[0];
 for (int value : arr) {
  if (maxValue < value) {
   maxValue = value;
  }
 }
 return maxValue;
}
// 获取最大值的长度
protected static int getNumLength(long num) {
 if (num == 0) {
  return 1;
 }
 int length = 0;
 for (long temp = num; temp != 0; temp /= 10) {
  length++;
 }
 return length;
}

8.4 图示

排序算法详解(java代码实现)

 


排序算法详解(java代码实现)

 

小伙伴们有兴趣想了解内容和更多相关学习资料的请点赞收藏+评论转发+关注我,后面会有很多干货。



Tags:排序算法   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
我们一起聊聊C#堆排序算法
前言堆排序是一种高效的排序算法,基于二叉堆数据结构实现。它具有稳定性、时间复杂度为O(nlogn)和空间复杂度为O(1)的特点。堆排序实现原理 构建最大堆:将待排序数组构建成一...【详细内容】
2023-10-10  Search: 排序算法  点击:(285)  评论:(0)  加入收藏
面试过程中常见的排序算法问题你见个?附常见排序算法源代码
在面试过程中,排序算法常常是一个重要的考点。排序算法的熟练掌握不仅能展现出候选人对基本数据结构的理解,也能展示出他们的算法设计和问题解决能力。下面我们将详细讨论几种...【详细内容】
2023-10-09  Search: 排序算法  点击:(88)  评论:(0)  加入收藏
目前世界上最快的排序算法-Timsort算法思想原理及C代码实现
排序算法在计算机科学中扮演着重要的角色,影响着各种应用程序的性能和效率。其中,Timsort 算法因其高效的性能和广泛的应用而备受瞩目。在本文中,我们将深入探究 Timsort 算法...【详细内容】
2023-08-05  Search: 排序算法  点击:(287)  评论:(0)  加入收藏
详解 DeepMind 排序算法
作者 | Justine Tunney译者 | 弯月责编 | 夏萌出品 | CSDN(ID:CSDNnews)近日,DeepMind 在博客发表了一篇阐述排序算法内核的论文。他们借鉴了构建 AlphaGo 积累的有关深度学习的...【详细内容】
2023-06-20  Search: 排序算法  点击:(189)  评论:(0)  加入收藏
AlphaDev将排序算法提速70%!C语言库作者一文详解DeepMind最新AI
图片来源:由无界 AI&zwnj; 生成几天前,DeepMind推出了AlphaDev,直接把排序算法提速70%。这一全新AI系统,便是基于下棋高手AlphaGo打造。而这项研究恰恰激起了前谷歌研究人员Just...【详细内容】
2023-06-20  Search: 排序算法  点击:(150)  评论:(0)  加入收藏
AI重写排序算法,速度快70%:DeepMind AlphaDev革新计算基础
计算的基础就此改变了。「通过交换和复制移动,AlphaDev 跳过了一个步骤,以一种看似错误,但实际上是捷径的方式连接项目。」这种前所未见、违反直觉的思想不禁让人回忆起 2016...【详细内容】
2023-06-08  Search: 排序算法  点击:(374)  评论:(0)  加入收藏
Go 语言实现快速排序算法
快速排序是由东尼&middot;霍尔所发明的一种排序算法,时间复杂度是 O(nlogn), 是不稳定排序算法。快速排序使用分治思想,通过一趟排序将要排序的数据分割成独立的两部分,其中一部...【详细内容】
2023-05-08  Search: 排序算法  点击:(358)  评论:(0)  加入收藏
看动图学算法:冒泡排序算法的原理和Java讲解
冒泡算法是一种简单的排序算法,它的基本思想是通过相邻元素之间的比较和交换,将大的元素慢慢地“冒泡”到数组的最后一个位置。冒泡算法在实现上非常简单,但它的时间复杂度较高...【详细内容】
2023-05-06  Search: 排序算法  点击:(369)  评论:(0)  加入收藏
常用的排序算法
排序算法是计算机科学领域中非常重要的基础算法之一,主要应用于数据处理中,将未排序的数据按照一定规则排列,以便后续的计算和数据分析。目前常用的排序算法有多种,包括冒泡排...【详细内容】
2023-04-27  Search: 排序算法  点击:(353)  评论:(0)  加入收藏
简述几种常用的排序算法
本文分享自华为云社区《深入浅出八种排序算法-云社区-华为云》,作者:嵌入式视觉 。归并排序和快速排序是两种稍微复杂的排序算法,它们用的都是分治的思想,代码都通过递归来实现,...【详细内容】
2023-03-27  Search: 排序算法  点击:(155)  评论:(0)  加入收藏
▌简易百科推荐
小红书、视频号、抖音流量算法解析,干货满满,值得一看!
咱们中国现在可不是一般的牛!网上的网友已经破了十个亿啦!到了这个互联网的新时代,谁有更多的人流量,谁就能赢得更多的掌声哦~抖音、小红书、、视频号,是很多品牌必争的流量洼地...【详细内容】
2024-02-23  二手车小胖说    Tags:流量算法   点击:(18)  评论:(0)  加入收藏
雪花算法详解与Java实现:分布式唯一ID生成原理
SnowFlake 算法,是 Twitter 开源的分布式 ID 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 ID。在分布式系统中的应用十分广泛,且 ID 引入了时间戳...【详细内容】
2024-02-03   一安未来  微信公众号  Tags:雪花算法   点击:(54)  评论:(0)  加入收藏
程序开发中常用的十种算法,你用过几种?
当编写程序时,了解和使用不同的算法对解决问题至关重要。以下是C#中常用的10种算法,每个算法都伴随着示例代码和详细说明。1. 冒泡排序 (Bubble Sort):冒泡排序是一种简单的比...【详细内容】
2024-01-17  架构师老卢  今日头条  Tags:算法   点击:(46)  评论:(0)  加入收藏
百度推荐排序技术的思考与实践
本文将分享百度在推荐排序方面的思考与实践。在整个工业界的推广搜场景上,特征设计通常都是采用离散化的设计,需要保证两方面的效果,一方面是记忆,另一方面是泛化。特征都是通过...【详细内容】
2024-01-09  DataFunTalk  微信公众号  Tags:百度推荐   点击:(80)  评论:(0)  加入收藏
什么是布隆过滤器?如何实现布隆过滤器?
以下我们介绍了什么是布隆过滤器?它的使用场景和执行流程,以及在 Redis 中它的使用,那么问题来了,在日常开发中,也就是在 Java 开发中,我们又将如何操作布隆过滤器呢?布隆过滤器(Blo...【详细内容】
2024-01-05  Java中文社群  微信公众号  Tags:布隆过滤器   点击:(94)  评论:(0)  加入收藏
面向推荐系统的深度强化学习算法研究与应用
随着互联网的快速发展,推荐系统在各个领域中扮演着重要的角色。传统的推荐算法在面对大规模、复杂的数据时存在一定的局限性。为了解决这一问题,深度强化学习算法应运而生。本...【详细内容】
2024-01-04  数码小风向    Tags:算法   点击:(106)  评论:(0)  加入收藏
非负矩阵分解算法:从非负数据中提取主题、特征等信息
非负矩阵分解算法(Non-negativeMatrixFactorization,简称NMF)是一种常用的数据分析和特征提取方法,主要用于从非负数据中提取主题、特征等有意义的信息。本文将介绍非负矩阵分解...【详细内容】
2024-01-02  毛晓峰    Tags:算法   点击:(75)  评论:(0)  加入收藏
再谈前端算法,你这回明白了吗?
楔子 -- 青蛙跳台阶一只青蛙一次可以跳上一级台阶,也可以跳上二级台阶,求该青蛙跳上一个n级的台阶总共需要多少种跳法。分析: 当n=1的时候,①只需要跳一次即可;只有一种跳法,即f(...【详细内容】
2023-12-28  前端爱好者  微信公众号  Tags:前端算法   点击:(114)  评论:(0)  加入收藏
三分钟学习二分查找
二分查找是一种在有序数组中查找元素的算法,通过不断将搜索区域分成两半来实现。你可能在日常生活中已经不知不觉地使用了大脑里的二分查找。最常见的例子是在字典中查找一个...【详细内容】
2023-12-22  小技术君  微信公众号  Tags:二分查找   点击:(79)  评论:(0)  加入收藏
强化学习算法在资源调度与优化中的应用
随着云计算和大数据技术的快速发展,资源调度与优化成为了现代计算系统中的重要问题。传统的资源调度算法往往基于静态规则或启发式方法,无法适应动态变化的环境和复杂的任务需...【详细内容】
2023-12-14  职场小达人欢晓    Tags:算法   点击:(169)  评论:(0)  加入收藏
站内最新
站内热门
站内头条