算法——排序算法

目录

1、冒泡排序

2、插入排序

3、选择排序

4、归并排序

5、快速排序

 6、堆排序

 7、计数排序

 8、桶排序

 9、基数排序


常见的排序算法包括:

  1. 冒泡排序(Bubble Sort)
  2. 插入排序(Insertion Sort)
  3. 选择排序(Selection Sort)
  4. 归并排序(Merge Sort)
  5. 快速排序(Quick Sort)
  6. 堆排序(Heap Sort)
  7. 计数排序(Counting Sort)
  8. 桶排序(Bucket Sort)
  9. 基数排序(Radix Sort)

1、冒泡排序

  • 工作原理:
    • 1、比较相邻的两个元素。如果前面的元素大于后面的元素,则交换它们的位置;
    • 2、对每一对相邻的元素进行同样的操作,从开始第一对到结尾的最后一对,这样一趟比较结束后,最大的元素就"沉"到了数列的最末尾;
    • 3、针对所有的元素重复以上的步骤,除了最后一个;
    • 4、重复步骤1~3,当没有相邻的元素需要交换时,排序就完成了。

冒泡排序示例代码:

public class BubbleSort {public static void main(String[] args) {int[] arr = {5, 2, 9, 1, 5, 6};bubbleSort(arr);System.out.println("\n排序后的数组:");for (int num : arr) {System.out.print(num + " ");}}public static void bubbleSort(int[] arr) {int n = arr.length;boolean swapped;for (int i = 0; i < n - 1; i++) {swapped = false;for (int j = 0; j < n - i - 1; j++) {if (arr[j] > arr[j + 1]) {// 交换 arr[j] 和 arr[j + 1]int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;swapped = true;}}// 如果没有发生交换,说明数组已经有序if (!swapped) {break;}}}
}

2、插入排序

  • 工作原理:
    • 从第一个元素开始,该元素可以认为已经被排序。
    • 取出下一个元素,在已经排序的元素序列中从后向前扫描。
    • 如果该元素(已排序)大于新元素,将该元素移到下一位置。
    • 重复步骤 3,直到找到已排序的元素小于或等于新元素的位置。
    • 将新元素插入到该位置后。
    • 重复步骤 2~5,数组经过 n-1 次遍历后就会变成有序序列。

插入排序示例代码:

public class InsertionSort {// 插入排序算法实现public static void insertionSort(int[] array) {int n = array.length;// 从第二个元素开始遍历数组for (int i = 1; i < n; i++) {int key = array[i]; // 当前要插入的值int j = i - 1; // 已排序部分的最后一个元素的下标// 在已排序部分中寻找合适的位置插入keywhile (j >= 0 && array[j] > key) {array[j + 1] = array[j]; // 向后移动元素j--;}array[j + 1] = key; // 将key插入合适的位置}}public static void main(String[] args) {int[] arr = {12, 11, 13, 5, 6};insertionSort(arr);System.out.print("Sorted array: ");for (int i : arr) {System.out.print(i + " ");}}
}

3、选择排序

  • 工作原理:
    • 1、首先,从未排序的元素中找到最小(或最大)的元素。
    • 2、将其放到已排序序列的末尾(或者放到另一个数组的开头)。
    • 3、然后,再从剩余的未排序元素中找到最小(或最大)的元素,放到已排序序列的末尾。
    • 4、重复步骤 2 和步骤 3,直到所有元素都已排序。

 选择排序的伪代码:

function selectionSort(array)n = array.lengthfor i from 0 to n-1minIndex = ifor j from i+1 to n-1if array[j] < array[minIndex]minIndex = jswap array[i] and array[minIndex]end for
end function
//外层循环遍历数组,
//内层循环找到未排序部分中的最小元素,并将其与当前外层循环位置的元素交换,
//这样就不断地将最小元素放到已排序部分的末尾,直到整个数组都排序完成

4、归并排序

  • 工作原理:

    • 分解:将待排序的数组不断地二分,直到每个子序列只有一个元素为止。

    • 排序:对每个子序列进行排序,可以采用递归的方式来实现。

    • 合并:将排好序的子序列再合并为一个整体有序的数组。

归并排序示例代码:

public class MergeSort {// 归并排序的主函数,对数组array进行归并排序public static void mergeSort(int[] array, int left, int right) {if (left < right) {// 计算中间位置int middle = (left + right) / 2;// 递归地对左半部分进行归并排序mergeSort(array, left, middle);// 递归地对右半部分进行归并排序mergeSort(array, middle + 1, right);// 合并左右两部分merge(array, left, middle, right);}}// 将两个已经排序的数组段 array[left...middle] 和 array[middle+1...right] 合并成一个有序数组public static void merge(int[] array, int left, int middle, int right) {// 计算左右两部分数组段的长度int n1 = middle - left + 1;int n2 = right - middle;// 创建临时数组存储左右两部分的数据int[] leftArray = new int[n1];int[] rightArray = new int[n2];// 将数据拷贝到临时数组for (int i = 0; i < n1; i++) {leftArray[i] = array[left + i];}for (int i = 0; i < n2; i++) {rightArray[i] = array[middle + i + 1];}// 合并左右两部分数组段int i = 0, j = 0;int k = left;while (i < n1 && j < n2) {if (leftArray[i] <= rightArray[j]) {array[k] = leftArray[i];i++;} else {array[k] = rightArray[j];j++;}k++;}// 将剩余的元素拷贝到数组中while (i < n1) {array[k] = leftArray[i];i++;k++;}while (j < n2) {array[k] = rightArray[j];j++;k++;}}
}

5、快速排序

工作原理:

  • 选取一个基准元素(通常选择第一个元素),将序列分割为两个子序列;
  • 将小于基准的元素放在基准的左边,大于基准的元素放在右边;
  • 对左右子序列分别进行递归快速排序;
  • 合并左右子序列。

快速排序的示例代码:

public class QuickSort {public static void main(String[] args) {int[] arr = {5, 2, 9, 3, 7, 6, 1, 8, 4};quickSort(arr, 0, arr.length - 1); // 调用快速排序算法for (int i : arr) {System.out.print(i + " "); // 输出排序后的数组}}public static void quickSort(int[] arr, int low, int high) {if (arr == null || arr.length == 0 || low >= high) {return; // 如果数组为空或者low大于等于high,直接返回}int middle = low + (high - low) / 2; // 计算中间值的索引int pivot = arr[middle]; // 取得中间值作为基准值int i = low, j = high; // 初始化i和j作为左右指针while (i <= j) { // 当i小于等于j时循环while (arr[i] < pivot) { // 在左半部分找到第一个大于等于基准值的元素i++;}while (arr[j] > pivot) { // 在右半部分找到第一个小于等于基准值的元素j--;}if (i <= j) { // 如果左指针小于等于右指针int temp = arr[i]; // 交换arr[i]和arr[j]arr[i] = arr[j];arr[j] = temp;i++;j--;}}if (low < j) { // 递归处理左半部分quickSort(arr, low, j);}if (high > i) { // 递归处理右半部分quickSort(arr, i, high);}}
}

 6、堆排序

工作原理:

  • 构建堆:首先将待排序的数据构建成一个二叉堆,可以是最大堆或最小堆。这个步骤可以使用从下往上的循环方式,从最后一个非叶子节点开始,逐个向前调整节点使得以当前节点为根的子树满足堆的性质。

  • 排序:将堆顶元素(最大值或最小值)与堆的最后一个元素交换位置,并将堆的大小减一。接着调整交换后的堆,使其满足堆的性质。重复以上步骤,直到整个数组排序完成。

堆排序的示例代码:

  1. 统计每个元素出现的次数:遍历待排序的数组,统计每个元素出现的次数,可以使用额外的辅助数组来保存计数结果。
  2. 根据元素的计数信息,确定元素在排序后的位置:根据元素值和它在计数数组中的计数位置,确定元素在排序后的位置。
  3. 将元素放置到正确的位置上:遍历待排序的数组,根据元素值在计数数组中的位置,将元素放置到正确的位置上。
  4. 输出排序后的结果:将排序后的元素依次输出,即得到排好序的数组。
public class HeapSort {// 堆排序的主要入口方法,用于对整个数组进行排序public static void sort(int[] arr) {// 构建最大堆buildMaxHeap(arr);// 从最后一个非叶子节点开始,依次将根节点与末尾元素交换,并重新调整堆for (int i = arr.length - 1; i > 0; i--) {swap(arr, 0, i); // 将根节点与末尾元素交换adjustHeap(arr, 0, i); // 重新调整堆}}// 构建最大堆的方法private static void buildMaxHeap(int[] arr) {int lastIndex = arr.length - 1;int parentIndex = (lastIndex - 1) / 2; // 最后一个非叶子节点的下标for (int i = parentIndex; i >= 0; i--) {adjustHeap(arr, i, arr.length);}}// 调整堆的方法,使其满足最大堆的性质private static void adjustHeap(int[] arr, int index, int length) {int temp = arr[index]; // 当前父节点for (int k = 2 * index + 1; k < length; k = 2 * k + 1) { // 从index结点的左子结点开始,也就是2*index+1处开始if (k + 1 < length && arr[k] < arr[k + 1]) { // 如果左子结点小于右子结点,k指向右子结点k++;}if (arr[k] > temp) { // 如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)arr[index] = arr[k];index = k;} else {break;}}arr[index] = temp; // 将temp值放到最终的位置}// 交换数组中两个元素的方法private static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}// 测试方法public static void main(String[] args) {int[] arr = {4, 6, 8, 5, 9, 1, 2, 3, 7};sort(arr);for (int num : arr) {System.out.print(num + " ");}}
}

 7、计数排序

工作原理:

  • 统计每个元素出现的次数:遍历待排序的数组,统计每个元素出现的次数,可以使用额外的辅助数组来保存计数结果。
  • 根据元素的计数信息,确定元素在排序后的位置:根据元素值和它在计数数组中的计数位置,确定元素在排序后的位置。
  • 将元素放置到正确的位置上:遍历待排序的数组,根据元素值在计数数组中的位置,将元素放置到正确的位置上。
  • 输出排序后的结果:将排序后的元素依次输出,即得到排好序的数组。

计数排序的示例代码:

public class CountingSortExample {public static void countingSort(int[] array, int max) {int[] count = new int[max + 1]; // 创建计数数组,并初始化为 0for (int num : array) {count[num]++; // 统计每个元素的个数}int k = 0;for (int i = 0; i < count.length; i++) {while (count[i] > 0) {array[k] = i;  // 将计数数组中的元素按顺序填充到原始数组中k++;count[i]--;}}}public static void main(String[] args) {int[] array = {4, 2, 2, 8, 3, 3, 1};int max = 8; // 数组中的最大值System.out.println("Before sorting: " + Arrays.toString(array));countingSort(array, max);System.out.println("After sorting: " + Arrays.toString(array));}
}

 8、桶排序

工作原理:

  • 遍历待排序数组,根据预设的规则将元素分配到对应的桶中。
  • 对每个桶内的元素进行排序,可以选择使用插入排序、快速排序等方法。
  • 将各个桶中的元素按顺序合并起来,得到最终的有序数组。
import java.util.ArrayList;
import java.util.Collections;public class BucketSort {public static void bucketSort(int[] nums) {int bucketSize = 5; // 设置桶的大小int maxValue = Integer.MIN_VALUE;int minValue = Integer.MAX_VALUE;for (int num : nums) {maxValue = Math.max(maxValue, num); // 找到待排序数组的最大值minValue = Math.min(minValue, num); // 找到待排序数组的最小值}int bucketCount = (maxValue - minValue) / bucketSize + 1; // 计算桶的个数ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(bucketCount);for (int i = 0; i < bucketCount; i++) {buckets.add(new ArrayList<>()); // 初始化桶}for (int num : nums) {int bucketIndex = (num - minValue) / bucketSize; // 计算元素应该放入的桶的索引buckets.get(bucketIndex).add(num); // 将元素放入对应的桶中}int index = 0;for (ArrayList<Integer> bucket : buckets) {Collections.sort(bucket); // 对每个桶内的元素进行排序for (int num : bucket) {nums[index++] = num; // 将排序好的元素放回原数组}}}public static void main(String[] args) {int[] arr = {29, 25, 3, 49, 9, 37, 21, 43};bucketSort(arr);for (int num : arr) {System.out.print(num + " ");}}
}

 9、基数排序

工作原理:

  • 首先,将待排序的整数按照个位数的数值进行分配到 "桶" 中。
  • 然后,按照个位数的顺序将桶中的数字依次取出,组成一个新的序列。
  • 接着,再以十位数的数值进行分配到对应的桶中,并按顺序取出,形成新的序列。
  • 最后,以此类推,直到所有位数都分配完毕,得到有序的序列。

基数排序的示例代码:

import java.util.ArrayList;public class RadixSort {// 获取数字的指定位数的数字public static int getDigit(int number, int digitPlace) {return (number / digitPlace) % 10;}// 基数排序函数public static void radixSort(int[] arr) {// 找出数组中的最大值,以确定需要多少位数int max = arr[0];for (int num : arr) {if (num > max) {max = num;}}// 计算最大值的位数int numDigits = 1;while (max > 9) {max /= 10;numDigits++;}// 创建 10 个桶ArrayList<ArrayList<Integer>> buckets = new ArrayList<>();for (int i = 0; i < 10; i++) {buckets.add(new ArrayList<>());}// 进行排序for (int digit = 1; digit <= Math.pow(10, numDigits - 1); digit *= 10) {// 将数字分配到对应的桶中for (int num : arr) {int digitVal = getDigit(num, digit);buckets.get(digitVal).add(num);}// 从桶中取出数字,并按顺序放回原数组int index = 0;for (int i = 0; i < 10; i++) {for (int num : buckets.get(i)) {arr[index++] = num;}buckets.get(i).clear(); // 清空桶,以便下一轮排序使用}}}// 测试public static void main(String[] args) {int[] arr = {170, 45, 75, 90, 802, 24, 2, 66};radixSort(arr);System.out.print("排序后的数组:");for (int num : arr) {System.out.print(num + " ");}}
}

一、1023: [编程入门]选择排序

题目描述
用选择法对10个整数从小到大排序。
输入格式
输入10个无序的数字
输出格式
排序好的10个整数
样例输入
4 85 3 234 45 345 345 122 30 12
样例输出
3
4
12
30
45
85
122
234
345
345

import java.util.*;
public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int[] array=new int[10];for(int i=0;i<10;i++) {array[i]=scanner.nextInt();}selectionSort(array);}public static void selectionSort(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;//更新最小元素的下标}}//将其放到已排序序列的末尾(0到i为已排序,j到n-1为未排序)int temp=array[i];array[i]=array[minIndex];array[minIndex]=temp;}for(int i=0;i<10;i++) {System.out.println(array[i]);}}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/692314.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设计模式: 策略模式

文章目录 一、什么是策略模式二、策略模式结构三、使用场景案例分析1、使用场景2、案例分析&#xff08;1&#xff09;消除条件分支 一、什么是策略模式 策略模式是一种行为型设计模式&#xff0c;它允许定义一组算法&#xff0c;并将每个算法封装在独立的类中&#xff0c;使它…

代码随想录算法训练营第十八天|235.二叉搜索树的最近公共祖先,701.二叉搜索树中的插入操作,450.删除二叉搜索树节点

235.二叉搜索树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树节点 235.二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近…

基于Java+Springboot+vue体育用品销售商城平台设计和实现

基于JavaSpringbootvue体育用品销售商城平台设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写> 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领…

在 Vue 中将 DOM 导出为图片

你好&#xff0c;我是小白Coding日志&#xff0c;一个热爱技术的程序员。在这里&#xff0c;我分享自己在编程和技术世界中的学习心得和体会。希望我的文章能够给你带来一些灵感和帮助。欢迎来到我的博客&#xff0c;一起在技术的世界里探索前行吧&#xff01; 在日常的工作中&…

【 Maven 】花式玩法之多模块项目

目录 一、认识Maven多模块项目 二、maven如何定义项目的发布策略 2.1 版本管理 2.2 构建配置 2.3 部署和发布 2.4 依赖管理 2.5 发布流程 三、使用Jenkins持续集成Maven项目 四、总结 如果你有一个多模块项目&#xff0c;并且想将这些模块发布到不同的仓库或目标位置&…

在UE5中使用OverlayMaterial制作多材质效果

UE5.1中新增了OverlayMaterial&#xff0c;可以让物体套用2个材质球效果&#xff0c;如A材质球为正常材质内容&#xff0c;B材质球为菲涅尔&#xff0c;或是B材质球是法线外拓描边等&#xff0c;该功能类似Unity的多pass效果&#xff0c;方便了日常使用。 下面就讲将怎么用Ove…

开源软件的利弊

目录 开源软件 优势 免费 透明 可更改 可协作 影响力 坏处 安全隐患 良莠不齐 学习成本 持续性问题 未知风险 开源软件 开源软件是一种基于开放协作和共享的软件开发模式&#xff0c;其利弊对于软件产业和社会发展具有重要意义 优势 免费 谁能拒绝不要钱的东西…

多线程相关(1)

线程调度 线程状态&#xff1a;状态切换阻塞与唤醒阻塞唤醒 wait 与 sleep创建线程方式 线程是cpu任务调度的最小执行单位&#xff0c;每个线程拥有自己独立的程序计数器、虚拟机栈、本地方法栈。 线程状态&#xff1a; 线程状态包括&#xff1a;创建、就绪、运行、阻塞、死亡…

2024.2.20

使用多进程完成两个文件的拷贝&#xff0c;父进程拷贝前一半&#xff0c;子进程拷贝后一半&#xff0c;父进程回收子进程的资源 #include<myhead.h> int main(int argc, const char *argv[]) {char str[100]"";puts("please input str:");//从终端读…

软件实例分享,饭店餐饮会员卡管理系统怎么弄会员充值怎么记账

软件实例分享&#xff0c;饭店餐饮会员卡管理系统怎么弄会员充值怎么记账 一、前言 以下软件教程以 佳易王餐饮会员管理系统软件V16为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、会员可以登记电子会员卡或使用vip卡片 2、卡类型可以自由…

【LeetCode】无权图的最短路精选7题——单源、多源

目录 无权图的单源最短路问题&#xff1a; 1. 迷宫中离入口最近的出口&#xff08;中等&#xff09; 2. 最小基因变化&#xff08;中等&#xff09; 3. 单词接龙&#xff08;困难&#xff09; 4. 为高尔夫比赛砍树&#xff08;困难&#xff09; 无权图的多源最短路问题&a…

疾控中心污水采样过程中会遇到哪些困难

在疾控中心的污水采样过程中&#xff0c;可能会遇到多种困难。 首先&#xff0c;污水的成分可能非常复杂&#xff0c;包括各种细菌、病毒、寄生虫、重金属、化学物质等&#xff0c;这给采样带来了很大的挑战。其次&#xff0c;污水中的有害物质可能会对采样设备和人员造成损害…

预处理详解

目录 预定义符号介绍 ​编辑 预处理指令 #define #define 定义标识符 #define 定义宏 #define 替换规则 #define中#和##的使用 带副作用的宏参数 宏和函数的对比 命令行定义 预处理指令 #undef 预处理指令 #include 头文件被包含的方式&#xff1a; 本地文件包含 …

【Unity】【VR开发】Unity云同步功能使用心得

【背景】 有时出差,旅行等等也带着电脑,晚上想要继续编辑项目,就需要用到云同步功能。目前实践下来,发现有些内容可以同步,有些内容则是不可以同步的,总结如下。 【如何云同步一个本地项目】 UnityHub的项目面板中有两个选项卡:项目和云端项目。 鼠标挪动到想要云同步…

c++类和对象新手保姆级上手教学(中)

前言&#xff1a; 类和对象中篇&#xff0c;这里讲到的前4个默认成员函数&#xff0c;是类和对象中的重难点&#xff0c;许多资料上的讲法都非常抽象&#xff0c;难以理解&#xff0c;所以我作出这篇总结&#xff0c;分享学习经验&#xff0c;以便日后复习。 目录 6个默认成员…

土壤墒情监测站的工作原理

TH-TS600土壤墒情自动监测站是一种用于自动检测土壤墒情的仪器&#xff0c;它可以实时监测土壤的水分含量和温度&#xff0c;并将数据传输到数据中心或监测中心进行分析和处理。 土壤墒情自动监测站通常由传感器、数据采集器、数据传输设备和数据处理软件等部分组成。传感器是…

Laravel02 路由基本概念和用法 给视图传递请求参数

Laravel02 路由基本概念和用法 1. 路由的基本概念2. 给视图传递请求参数 1. 路由的基本概念 routes文件夹下的web.php是用来定义路由规则的。 自己定义一个路径 2. 给视图传递请求参数 在laravel里使用一个辅助函数request来快速获取请求参数

NX/UG二次开发—CAM—平面铣边界准确设置方法

大家在对平面铣设置边界时&#xff0c;经常遇到边界方向与自己期望的不一致&#xff0c;有些人喜欢用检查刀路是否过切来判断&#xff0c;但是对于倒角、负余量等一些情况&#xff0c;刀路本来就是过切的。对于多边界&#xff0c;可以根据选择的曲线来起点和面的方向来确定&…

Camera2 createCaptureSession源码分析

当应用调用CameraManager#openCamera获取到已打开的camera设备后&#xff0c;会调用createCaptureSession方法来完成camera stream创建和stream的相关配置。在createCaptureSession方法中&#xff0c;首先将应用的surfaces信息封装成可跨binder传递的OutputConfiguration对象&a…

ACE 中的Active Object模式

Active Object 设计模式&#xff1a; 1&#xff09; 根据对象被调用的方式&#xff0c;可以将对象分为两类: Passive Object和Active Object。Passive 和 Object和调用者在同一个线程中&#xff0c;这就是我们通常所用的函数调用。而Active Object和调用在不同的线程中&#xf…