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

排序算法详解(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:排序算法   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
排序算法大致分为内部排序和外部排序两种内部排序:待排序的记录全部放到内存中进行排序,时间复杂度也就等于比较的次数外部排序:数据量很大,内存无法容纳,需要对外存进行访问再排...【详细内容】
2022-06-08  Tags: 排序算法  点击:(0)  评论:(0)  加入收藏
冒泡排序是所有排序算法中最简单、最易实现的算法,有时也称为起泡排序算法。使用冒泡排序算法对 n 个数据进行排序,实现思路是:从待排序序列中找出一个最大值或最小值,这样的操...【详细内容】
2022-05-06  Tags: 排序算法  点击:(72)  评论:(0)  加入收藏
桶排序算法就是把数据平分到每一个桶中,然后对桶中的数据进行排序,再按桶的顺序依次倒出数据,桶排序算法很好理解。桶排序算法也是以空间换时间的算法。举例说明一下桶排序算法...【详细内容】
2022-03-24  Tags: 排序算法  点击:(50)  评论:(0)  加入收藏
10种经典排序算法包括冒泡排序、选择排序、快速排序、归并排序、堆排序、插入排序、希尔排序、计数排序、桶排序、基数排序等。当然,还有一些其他的排序算法,大家可以继续去...【详细内容】
2022-03-11  Tags: 排序算法  点击:(55)  评论:(0)  加入收藏
前言:本文章主要是讲解我个人在学习Java开发环境的排序算法时做的一些准备,以及个人的心得体会,汇集成本篇文章,作为自己对排序算法理解的总结与笔记。内容主要是关于十大经典排...【详细内容】
2022-03-04  Tags: 排序算法  点击:(58)  评论:(0)  加入收藏
一、什么是选择排序1.1、文字描述选择排序是一种简单直观的排序方式,它的工作原理是每一次排序时先从待处理数据元素中选择出一个最大(或最小)的元素,并存放在序列的末尾(起始)位...【详细内容】
2022-01-04  Tags: 排序算法  点击:(108)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15  Tags: 排序算法  点击:(97)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  Tags: 排序算法  点击:(116)  评论:(0)  加入收藏
1. 插入排序步骤:1.从第一个元素开始,该元素可以认为已经被排序2.取下一个元素tem,从已排序的元素序列从后往前扫描3.如果该元素大于tem,则将该元素移到下一位4.重复步骤3,直到找...【详细内容】
2021-08-19  Tags: 排序算法  点击:(162)  评论:(0)  加入收藏
人生有涯,学海无涯今天跟大家分享一个常用的排序算法&mdash;&mdash;快速排序。我想大家在日常的工作或者面试的时候肯定经常会遇到很多排序算法,而且快速排序算法往往是这里面...【详细内容】
2021-03-04  Tags: 排序算法  点击:(230)  评论:(0)  加入收藏
▌简易百科推荐
排序算法大致分为内部排序和外部排序两种内部排序:待排序的记录全部放到内存中进行排序,时间复杂度也就等于比较的次数外部排序:数据量很大,内存无法容纳,需要对外存进行访问再排...【详细内容】
2022-06-08  java研习社    Tags:排序算法   点击:(0)  评论:(0)  加入收藏
两篇文章,主要向大家展示了算法对于计算机来说有多重要,多神奇,性能提升效果显著。那二进制算法的思路是如何形成的呢?我们先从一道有趣的题目开始。 有100瓶药水,其中一瓶是毒药...【详细内容】
2022-06-06  还没禿的程序猿火华    Tags:算法   点击:(3)  评论:(0)  加入收藏
对于字符串匹配,如用一个长度为m的模式串去匹配一个长度为n的主串,我们可以使用暴力法(BF,Brute Force),其时间复杂度为O(m*n)。字符串匹配kmp算法的时间复杂度只需要O(m+n)。使用...【详细内容】
2022-06-01  小智雅汇    Tags:算法   点击:(12)  评论:(0)  加入收藏
md5和sha256信息摘要算法,都属于加密哈希函数,而且算法比较复杂。那么md5和sha256算法有什么区别,哪个的安全性比较高呢?关于md5的简介md5是一种被广泛使用的密码散列函数,可以产...【详细内容】
2022-05-23  哈客部落    Tags:md5   点击:(32)  评论:(0)  加入收藏
对于一名优秀的程序员来说,面对一个项目的需求的时候,一定会在脑海里浮现出最适合解决这个问题的方法是什么,选对了算法,就会起到事半功倍的效果,反之,则可能会使程序运行效率低下...【详细内容】
2022-05-19  活在信息时代    Tags:算法   点击:(3)  评论:(0)  加入收藏
【写在最前】 我们在平时的编程学习中,经常会接触到“正则表达式”这个概念; 但是很多小白傻傻分不清楚它的正确用法以及适用场景,甚至是在查阅了很多资料之后仍然是云山雾罩。...【详细内容】
2022-05-18  5分钟IT入门    Tags:正则表达式   点击:(41)  评论:(0)  加入收藏
问题:有一个5X6的灯矩阵,灯按一下就亮,再按一下就熄灭。现在有这样一种情况,在这个矩阵中任意按下一盏灯它本身以及它的上、下、左、右四个位置的灯的状态也会随之改变。例如:...【详细内容】
2022-05-11  小汪学python  今日头条  Tags:Python算法   点击:(34)  评论:(0)  加入收藏
//基于矩阵的三元组表示,将矩阵A转置为矩阵BFastTransposeTSMatrix(TSMatrix A,TSMatrix *B){ int col,t,p,q; int num[MAXSIZE],position[MAXSIZE]; B->len=A.len;B-N=A....【详细内容】
2022-04-24  碎冰冰的萝卜坑    Tags:稀疏矩阵   点击:(103)  评论:(0)  加入收藏
贪心算法概述贪心算法(又称贪婪算法),基本原理是,遵循某种既定原则,不断地选取当前条件下最优的选择来构造每一个子步骤,直到获得问题最终的求解。即在求解时,总是作出当前看来最好...【详细内容】
2022-04-22  北漂的乔峰    Tags:贪心算法   点击:(63)  评论:(0)  加入收藏
给定一个单词或整数数组,按字典顺序排列找到下一个排列例如,“gfg”的下一个排列是“ggf”,[1, 2, 3] 的下一个排列是 [1, 3, 2]。第一步:从后往前找到第一个破坏单调递增性质的...【详细内容】
2022-04-20  学海云舟    Tags:排列   点击:(42)  评论:(0)  加入收藏
站内最新
站内热门
站内头条