【算法刷题】七大排序算法总结(冒泡、选择、插入、归并、快速、希尔、堆排序)-程序员宅基地

技术标签: 算法  【算法刷题】  排序算法  数据结构  

在这里插入图片描述

七大排序算法总结

  • 经总结,排序算法大体可以分为以下七大种(含核心思想):
    1. 冒泡排序:通过相邻元素的比较和交换来将最大(或最小)的元素逐渐“冒泡”到数组的一端
    2. 选择排序:在未排序部分的数据中选择最小(或最大)的元素,然后将其放置到已排序部分的末尾
    3. 插入排序:将待排序的元素逐个插入到已排序部分的正确位置
    4. 归并排序:采用分治法,将已有序的子序列合并,得到完全有序的序列;
    5. 快速排序: 通过选取基准元素,将数组划分为两个子数组,并对子数组递归排序,实现整个数组的快速排序
    6. 希尔排序:通过较大间隔的插入排序来使数组中的元素局部有序,从而减少后续插入排序的工作量
    7. 堆排序:将待排序的元素构建成一个最大堆(大顶堆或最小堆),然后将堆顶元素与堆的最后一个元素交换,然后重新调整堆,使得剩余的元素仍然构成一个最大堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了

1.冒泡排序

  1. 核心思想: 通过相邻元素的比较和交换来将最大(或最小)的元素逐渐“冒泡”到数组的一端

    动图

  2. 具体步骤:

    1. 从数组的第一个元素开始,依次比较相邻的两个元素。
    2. 如果前一个元素大于后一个元素,则交换它们的位置,使得较大的元素“冒泡”到后面
    3. 继续进行相邻元素的比较和交换,直到数组的末尾
    4. 重复执行上述步骤,每次都会将当前未排序部分的最大元素“冒泡”到数组的末尾
    5. 重复执行上述步骤,直到整个数组排序完成。
  3. 实现代码:

    public static void bubbleSort(int[] arr) {
          
        int temp = 0;
        for (int i = arr.length - 1; i > 0; i--) {
           	// 每次需要排序的长度
            for (int j = 0; j < i; j++) {
           			// 从第一个元素到第i个元素
                if (arr[j] > arr[j + 1]) {
          			// 确保较大的元素排到后面
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
    
  4. 时间和空间复杂度:

    • 平均情况:O(n2)
    • 最好情况:O(n)
    • 最坏情况:O(n2)
    • 空间复杂度:O(1)
    • 稳定性:稳定
  5. 优化: 增加标记符swap,用于确定当前一轮冒泡是否有元素进行交换,若没有则跳出循环,表示数组已经有序了

    public static void bubbleSort(int[] arr) {
          
        int temp = 0;
        boolean swap;
        for (int i = arr.length - 1; i > 0; i--) {
           // 每次需要排序的长度
            swap=false;
            for (int j = 0; j < i; j++) {
           // 从第一个元素到第i个元素
                if (arr[j] > arr[j + 1]) {
          
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    swap=true;
                }
            }//loop j
            if (swap==false){
          			//前面的一轮循环没有进行交换,数组已经有序
                break;
            }
        }//loop i
    }// method bubbleSort
    

2.选择排序

  1. 核心思想: 在未排序部分的数据中选择最小(或最大)的元素,然后将其放置到已排序部分的末尾

  2. 具体步骤:

    1. 遍历数组,将第一个元素作为当前最小(或最大)元素。
    2. 在未排序部分的剩余元素中,找到最小(或最大)的元素,并记录其位置。
    3. 将找到的最小(或最大)元素与未排序部分的第一个元素交换位置,将其放置到已排序部分的末尾。
    4. 重复执行上述步骤,每次都会将当前未排序部分的最小(或最大)元素放置到已排序部分的末尾。
    5. 这样,经过n-1轮的遍历和交换,整个数组就会按照升序(或降序)排列。
  3. 实现代码:

    public static void selectionSort(int[] arr) {
          
        int temp, min = 0;
        for (int i = 0; i < arr.length - 1; i++) {
          
            min = i;
            // 循环查找最小值
            for (int j = i + 1; j < arr.length; j++) {
          
                if (arr[min] > arr[j]) {
          
                    min = j;
                }
            }
            if (min != i) {
          
                temp = arr[i];
                arr[i] = arr[min];
                arr[min] = temp;
            }
        }
    }
    
  4. 时间和空间复杂度:

    • 平均情况:O(n2)
    • 最好情况:O(n2)
    • 最坏情况:O(n2)
    • 空间复杂度:O(1)
    • 稳定性:不稳定
  5. 关于稳定性的探讨:

    • 稳定性:在排序过程中,相等元素的相对顺序是否会被改变。如果排序算法能够保持相等元素的相对顺序不变,则称其为稳定的排序算法;反之,则称其为不稳定的排序算法

    • 冒泡排序(升序):当相邻元素进行比较并需要交换位置时,只有当后面的元素小于前面的元素才会进行交换。因此,对于相等的元素,即使它们相邻,它们的相对顺序也不会被改变,从而保持了排序的稳定性

    • 选择排序:每次选择最小的元素并放置到已排序部分的末尾。在寻找最小(或最大)元素的过程中,可能会导致相等元素的相对顺序发生改变。例如,在一组相等的元素中,由于选择排序每次只选择一个最小(或最大)元素,所以在选择的过程中可能会交换这些相等元素的位置,从而导致排序的不稳定性

    • 举例:假设我们有以下一组待排序的元素:

      [5①, 2, 7, 5②, 1]
      
      • 冒泡排序:比较相邻的元素,并根据需要交换它们的位置。当遇到相等元素时,只有在后面的元素小于前面的元素时才会进行交换。

        第一轮冒泡排序:[2, 5①, 5②, 1, 7]
        第二轮冒泡排序:[2, 5, 1, 5, 7]
        第三轮冒泡排序:[2, 1, 5, 5, 7]
        第四轮冒泡排序:[1, 2, 5, 5, 7]
        
      • 选择排序:

        第一轮选择排序:[1, 2, 7, 5②, 5①](选择1) (两个相等的5的位置发生变化,不稳定!!!)
        第二轮选择排序:[1, 2, 5, 5, 7](选择2)
        第三轮选择排序:[1, 2, 5, 5, 7](选择5)
        第四轮选择排序:[1, 2, 5, 5, 7](选择5)
        第五轮选择排序:[1, 2, 5, 5, 7](选择7)
        

3.插入排序

  1. 核心思想:待排序的元素逐个插入到已排序部分的正确位置

    动图

  2. 具体步骤:

    1. 将数组分为已排序部分和未排序部分。一开始,已排序部分只包含第一个元素,即数组的第一个元素被认为是已排序的。
    2. 从未排序部分取出一个元素,将其插入到已排序部分的正确位置。为了找到正确的位置,可以从已排序部分的末尾开始,依次向前比较已排序元素,直到找到小于等于该元素的位置。
    3. 将该元素插入到找到的位置,并将已排序部分中的元素向后移动,为新元素腾出位置。
    4. 重复步骤2和步骤3,直到未排序部分为空。
    5. 最终,已排序部分即为排序好的数组。
  3. 实现代码:

    public static void insertionSort(int[] arr) {
          
        int n = arr.length;
        for (int i = 1; i < n; i++) {
          		//从第二个元素开始,第一个元素默认有序
        	int key = arr[i];				//保存当前元素 key
            int j = i - 1;
    		
            //找到合适的位置
            while (j >= 0 && arr[j] > key) {
          //发现已排序元素比 key 大,则将该元素向后移动一位,直到找到 key 的正确位置
            	arr[j + 1] = arr[j];
    			j = j - 1;					//往后移
            }	
            arr[j + 1] = key;1				//找到 key 保存的位置
       	}
    }
    
    待排序数组:[5, 2, 4, 6, 1, 3]
    1:[2, 5, 4, 6, 1, 3]
    2:[2, 4, 5, 6, 1, 3]
    3:[1, 2, 4, 5, 6, 3]
    4:[1, 2, 3, 4, 5, 6]
    
  4. 时间和空间复杂度:

    • 平均情况:O(n2)
    • 最好情况:O(n)
    • 最坏情况:O(n2)
    • 空间复杂度:O(1)
    • 稳定性:稳定

4.二分插入排序

  1. 核心思想:利用二分查找来确定待插入元素在已排序部分中的位置,以减少比较次数

  2. 实现步骤:

    1. 初始状态:将数组的第一个元素视为已排序部分,其余元素视为待排序部分。
    2. 插入过程:从第二个元素开始遍历待排序部分,对于每个元素,使用二分查找确定其在已排序部分中的插入位置。
    3. 二分查找:在已排序部分中,使用二分查找找到第一个大于待插入元素的位置,这个位置及之后的元素都需要向后移动一个位置来腾出空间。
    4. 插入操作:将待插入元素插入到找到的位置,完成一轮插入操作。
    5. 重复步骤2~4,直到待排序部分中的所有元素都被插入到已排序部分中,整个数组就被排序完成了。
  3. 实现代码:

    public static void binaryInsertionSort(int[] arr) {
          
        int n = arr.length;
        for (int i = 1; i < n; i++) {
          
            int key = arr[i];
            int left = 0;
            int right = i - 1;
    
            // 二分查找确定插入位置
            int insertIndex = binarySearch(arr, left, right, key);
    
            // 将大于 key 的元素向后移动一位
            for (int j = i - 1; j >= insertIndex; j--) {
          
                arr[j + 1] = arr[j];
            }
    
            // 插入 key
            arr[insertIndex] = key;
        }
    }
    
    // 二分查找
    private static int binarySearch(int[] arr, int left, int right, int key) {
          
        while (left <= right) {
          
            int mid = left + (right - left) / 2;
            if (arr[mid] == key) {
          
                return mid; // key 在已排序部分的位置
            } else if (arr[mid] < key) {
          
                left = mid + 1;
            } else {
          
                right = mid - 1;
            }
        }
        return left; // 返回待插入位置
    }
    
  4. 时间和空间复杂度:

    • 平均情况:O(n2)
    • 最好情况:O(n)
    • 最坏情况:O(n2)
    • 空间复杂度:O(1)
    • 稳定性:稳定

5.归并排序

  1. 核心思想: 采用分治法,将已有序的子序列合并,得到完全有序的序列;

  2. 步骤:

    1. 分解(Divide):将原始数组分解为较小的子数组,直到每个子数组只有一个元素为止。这可以通过递归的方式实现,将数组不断二分直到每个子数组的长度为1。
    2. 解决(Conquer):对每个子数组进行排序。对于只有一个元素的子数组来说,可以认为它们已经是有序的。
    3. 合并(Merge):合并相邻的子数组,形成一个更大的有序数组。合并过程中,需要按照大小顺序逐个比较两个子数组中的元素,并将较小(或较大)的元素依次放入一个临时数组中,直到合并完成。
    4. 递归合并(Recursively Merge):重复以上步骤,直到所有子数组都被合并成一个大的有序数组为止。

    动图

  3. 实现代码:

    public static void mergeSort(int[] arr){
          
        int[] temp =new int[arr.length];
        internalMergeSort(arr, temp, 0, arr.length-1);
    }
    private static void internalMergeSort(int[] arr, int[] temp, int left, int right){
          
        //当left==right的时,已经不需要再划分了
        if (left<right){
          
            int middle = (left+right)/2;
            internalMergeSort(arr, temp, left, middle);          //左子数组
            internalMergeSort(arr, temp, middle+1, right);       //右子数组
            mergeSortedArray(arr, temp, left, middle, right);    //合并两个子数组
        }
    }
    // 合并两个有序子序列
    private static void mergeSortedArray(int arr[], int temp[], int left, int middle, int right){
          
        int i=left;      
        int j=middle+1;
        int k=0;
        while (i<=middle && j<=right){
          
            temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
        }
        while (i <=middle){
          
            temp[k++] = arr[i++];
        }
        while ( j<=right){
          
            temp[k++] = arr[j++];
        }
        //把数据复制回原数组
        for (i=0; i<k; ++i){
          
            arr[left+i] = temp[i];
        }
    }
    
  4. 时间和空间复杂度:

    • 平均情况:O(nlogn)
    • 最好情况:O(nlogn)
    • 最坏情况:O(nlogn)
    • 空间复杂度:O(n)
    • 稳定性:稳定
  5. 适用场景: 归并排序在数据量比较大的时候也有较为出色的表现(效率上),但是,其空间复杂度O(n)使得在数据量特别大的时候(例如,1千万数据)几乎不可接受。而且,考虑到有的机器内存本身就比较小,因此,采用归并排序一定要注意。

6.快速排序

  1. 核心思想: 通过选取基准元素,将数组划分为两个子数组,并对子数组递归排序,实现整个数组的快速排序

  2. 实现步骤:

    1. 从数列中挑出一个元素,称为 “基准”(pivot),
    2. 重新排序数列,所有比基准值小的元素摆放在基准前面所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
    3. 递归地(recursively)把小于基准值元素的子数列大于基准值元素的子数列排序。
  3. 实现代码:

    public static void quickSort(int[] arr){
          
        qsort(arr, 0, arr.length-1);
    }
    
    private static void qsort(int[] arr, int low, int high){
          
        if (low >= high)
            return;
        int pivot = partition(arr, low, high);        //将数组分为两部分
        qsort(arr, low, pivot-1);                   //递归排序左子数组
        qsort(arr, pivot+1, high);                  //递归排序右子数组
    }
    
    private static int partition(int[] arr, int low, int high){
          
        int pivot = arr[low];     //基准
        while (low < high){
          
            
            while (low < high && arr[high] >= pivot){
          
                --high;
            } 
            
            arr[low]=arr[high];             //比基准小的元素会被移动到基准的左边
            
            while (low < high && arr[low] <= pivot){
          
                ++low;
            }
            
            arr[high] = arr[low];           //比基准大的元素会被移动到基准的右边
        }
        //扫描完成,基准到位
        arr[low] = pivot;
        //返回的是基准的位置
        return low;
    }
    
  4. 举例:

    初始:[7, 2, 1, 6, 8, 5, 3, 4]	# 7为基准
    	 
    第一:[4, 2, 1, 6, 8, 5, 3, 4] # 4移到左边
    	 [4, 2, 1, 6, 8, 5, 3, 8] # 8移到右边
    	 [4, 2, 1, 6, 3, 5, 3, 8] # 3移到左边
    	 [4, 2, 1, 6, 3, 5, 7, 8] # 基准7插入到low位置
    	 
    划分为两个数组:[4, 2, 1, 6, 3, 5]和[8]
    第二: [4, 2, 1, 6, 3, 5] # 以4为基准
    	  [3, 2, 1, 6, 3, 5] # 3移到左边
    	  [3, 2, 1, 6, 6, 5] # 6移到右边
    	  [3, 2, 1, 4, 6, 5] # 基准4插入到low位置
    	 
    以此类推......
    
  5. 时间和空间复杂度:

    • 平均情况:O(nlogn)
    • 最好情况:O(nlogn)
    • 最坏情况:O(n2)
    • 空间复杂度:O(logn)~O(n)
    • 稳定性:不稳定

7.希尔排序

  1. 核心思想: 通过较大间隔的插入排序来使数组中的元素局部有序,从而减少后续插入排序的工作量

  2. 实现步骤:

    • 选择增量序列:希尔排序的关键是选择增量序列,即确定每次分割子序列的间隔。通常选择的增量序列是经过优化的,以达到更好的排序效果。常见的增量序列有希尔增量序列(1, 4, 13, 40…)、Hibbard增量序列(1, 3, 7, 15…)等。
    • 对子序列进行插入排序:根据选择的增量序列,将待排序数组分割成若干个子序列,对每个子序列进行插入排序。插入排序会使得每个子序列局部有序。
    • 逐步缩小增量:重复以上步骤,逐步缩小增量,直到增量为1。当增量为1时,整个数组变为一个序列,此时进行最后一次插入排序即可完成排序。
  3. 实现代码:

    public class ShellSort {
          
        public static void shellSort(int[] arr) {
          
            int n = arr.length;
            
            // 初始化增量,这里使用希尔增量序列
            int gap = 1;
            while (gap < n / 3) {
          
                gap = gap * 3 + 1;
            }
            
            // 增量逐步缩小至1
            while (gap > 0) {
          
                // 对每个子序列进行插入排序
                for (int i = gap; i < n; i++) {
          
                    int temp = arr[i];
                    int j = i;
                    // 对当前子序列进行插入排序
                    while (j >= gap && arr[j - gap] > temp) {
          
                        arr[j] = arr[j - gap];
                        j -= gap;
                    }
                    arr[j] = temp;
                }
                // 缩小增量
                gap = gap / 3;
            }
        }
    
        public static void main(String[] args) {
          
            int[] arr = {
          12, 34, 54, 2, 3};
            shellSort(arr);
            System.out.println("排序后的数组:");
            for (int num : arr) {
          
                System.out.print(num + " ");
            }
        }
    }
    
  4. 时间和空间复杂度:

    • 平均情况:O(nlogn)—O(n2)
    • 最好情况:O(1.3n)
    • 最坏情况:O(n2)
    • 空间复杂度:O(1)
    • 稳定性:不稳定

8.堆排序(重要)

8.1堆概念

  1. 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;
  2. 或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:

img

同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子

该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

8.2核心思想、实现步骤

  1. 核心思想:将待排序的元素构建成一个最大堆(大顶堆或最小堆),然后将堆顶元素与堆的最后一个元素交换,然后重新调整堆,使得剩余的元素仍然构成一个最大堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
  2. 实现步骤:
    1. 将无序序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
    2. 将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
    3. 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

8.3举例

  1. 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。

    • 假设给定无序序列结构如下:

      img

    • 此时我们从最后一个非叶子结点开始(叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整。

      img

    • 找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换。

      img

    • 这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6

      img

    • 此时,我们就将一个无需序列构造成了一个大顶堆。

  2. 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。

    • 将堆顶元素9和末尾元素4进行交换:

      img

    • 重新调整结构,使其继续满足堆定义:

      img

    • 再将堆顶元素8与末尾元素5进行交换,得到第二大元素8:

      img

  3. 后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序

    img

8.4代码举例

import java.util.Arrays;
public class Main{
    
    public static void main(String[] args) {
    
        int[] arr = new int[]{
    4,6,8,5,9};
        int length = arr.length;
        //从最后一个非叶节点开始构建大顶堆
        for (int i = arr.length/2-1; i >=0; i--) {
    
            maximumHeap(i,arr,length);
        }
        //从最小的叶子节点开始与根节点进行交换并重新构建大顶堆
        for (int i = arr.length-1; i >=0; i--) {
    
//            System.out.println(Arrays.toString(arr));
            swap(arr,0,i);
            length--;
            maximumHeap(0,arr,length);
        }
        System.out.println(Arrays.toString(arr));
    }
    //构建大顶堆
    public static void maximumHeap(int i,int[] arr,int length){
    
        int temp = arr[i];
        for (int j = i*2+1; j < length; j=j*2+1) {
    
            //如果右孩子大于做孩子,则指向右孩子
            if(j+1<length && arr[j+1]>arr[j]){
    
                j++;
            }
            //如果最大的孩子大于当前节点,则将大孩子赋给当前节点,修改当前节点为其大孩子节点,再向下走。
            if(arr[j]>temp){
    
                arr[i] = arr[j];
                i = j;
            }else{
    
                break;
            }
        }
        //将temp放到最终位置
        arr[i] = temp;
    }
    //交换
    public static void swap(int[] arr,int i,int j){
    
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

8.5时间空间复杂度

1. 时间复杂度: 堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)…1]逐步递减,近似为nlogn。所以堆排序时间复杂度最好和最坏情况下都是**O(nlogn)**级。

2. 空间复杂度:堆排序不要任何辅助数组,只需要一个辅助变量,所占空间是常数与n无关,所以空间复杂度为O(1)

9.总结

排序 排序方法 平均情况 最好情况 最坏情况 空间 稳定性
1 冒泡排序 O(n2) O(n) O(n2) O(1) 稳定
2 选择排序 O(n2) O(n2) O(n2) O(1) 不稳定
3 插入排序 O(n2) O(n) O(n2) O(1) 稳定
4 二分插入排序 O(n2) O(n) O(n2) O(1) 稳定
5 归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定
6 快速排序 O(nlogn) O(nlogn) O(n2) O(logn)~O(n) 不稳定
7 希尔排序 O(nlogn) ~ O(n2) O(n1.3) O(n2) O(1) 不稳定
8 堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定

在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_61440595/article/details/137544037

智能推荐

分布式光纤传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告_预计2026年中国分布式传感器市场规模有多大-程序员宅基地

文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大

07_08 常用组合逻辑电路结构——为IC设计的延时估计铺垫_基4布斯算法代码-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码

OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版

关于美国计算机奥赛USACO,你想知道的都在这_usaco可以多次提交吗-程序员宅基地

文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗

MySQL存储过程和自定义函数_mysql自定义函数和存储过程-程序员宅基地

文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程

半导体基础知识与PN结_本征半导体电流为0-程序员宅基地

文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0

随便推点

【Unity3d Shader】水面和岩浆效果_unity 岩浆shader-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader

广义线性模型——Logistic回归模型(1)_广义线性回归模型-程序员宅基地

文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计_垃圾分类网页设计目标怎么写-程序员宅基地

文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写

C# .Net 发布后,把dll全部放在一个文件夹中,让软件目录更整洁_.net dll 全局目录-程序员宅基地

文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录

BRIEF特征点描述算法_breif description calculation 特征点-程序员宅基地

文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点

房屋租赁管理系统的设计和实现,SpringBoot计算机毕业设计论文_基于spring boot的房屋租赁系统论文-程序员宅基地

文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文