三个数的排序
题目:输入三个整数x,y,z,请把这三个数由小到大输出
输入:输入数据包含3个整数x,y,z,分别用逗号隔开
输出:输出由小到大排序后的结果,用空格隔开
输入:2,1,3
输出:1 2 3
import java.util.Arrays;
import java.util.Scanner;
public class 三个数排序 {
public static void main(String[] args) {
int[] num = new int[3];
Scanner sc = new Scanner(System.in);
System.out.println("请输入3个整数:");
num[0] = sc.nextInt();
num[1] = sc.nextInt();
num[2] = sc.nextInt();
Arrays.sort(num);
System.out.println("从小到大排序后的结果:");
for (int i = 0; i < num.length; i++) {
System.out.print(num[i]+"\t");
}
}
}
知识点
排序
所谓排序就是按照其中的某个或某些关键字的大小,按照升序或者降序的方式把他们排列起来的操作。
| 排序算法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 |
|---|---|---|---|---|---|
| 冒泡排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 |
| 选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
| 插入排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 |
| 希尔排序 | O(n log n) | O(n^2) | O(n) | O(1) | 不稳定 |
| 归并排序 | O(n log n) | O(n log n) | O(n log n) | O(n) | 稳定 |
| 快速排序 | O(n log n) | O(n^2) | O(n log n) | O(log n) | 不稳定 |
| 堆排序 | O(n log n) | O(n log n) | O(n log n) | O(1) | 不稳定 |
| 计数排序 | O(n+k) | O(n+k) | O(n+k) | O(k) | 稳定 |
| 桶排序 | O(n^2) | O(n^2) | O(n) | O(n+k) | 稳定 |
| 基数排序 | O(n*k) | O(n*k) | O(n*k) | O(n+k) | 稳定 |
冒泡排序
一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就交换位置。这个过程持续对数列的末尾进行,直到整个数列都排序完成。


public static void bubbleSort(int[] array){
for(int i = 0;i < array.length - 1;i++){
//flag 是用来判断数组中元素是否经过交换
boolean flag = true;
for(int j = 0;j < array.length - i - 1;j++){
if(array[j] > array[j + 1]){
swap(array,j,j + 1);
flag = false;
}
}
if(flag){
return;
}
}
}
public static void swap(int[] array,int i,int j){
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
选择排序
一种简单的比较排序算法,它将数组分为已排序和未排序两部分,每次从未排序部分选择最小的元素并将其放入已排序部分。它的时间复杂度为O(n^2),不适用于大规模数据集。


public static void selectSort(int[] array){
for(int i = 0;i < array.length - 1;i++){
int maxIndex = 0;
for(int j = 0;j < array.length - i;j++){
if(array[j] > array[maxIndex]){
maxIndeex = j;
}
}
swap(array,maxIndex,array.length - i - 1);
}
}
public static void swap(int[] array,int i,int j){
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
插入排序
就是从无序区间中拿出元素,直接插入到有序区间中,知道无序区间的长度为0时,可以得到一个有序序列。


public static void insertSort(int[] array){
//有序数组:[0 , i] 无序数组:[i + 1, array.length]
for(int i = 0;i < array.length - 1;i++){
int x = array[i + 1];
int j;
for(j = i;j >= 0 && array[j] > x;j--){
array[j + 1] = array[j];
}
array[j + 1] = x;
}
}
快速排序
任取待排序序列中的某元素为基准值,按照大于基准值,小于基准值的规则,左子序列中为小于基准值的元素,右子序列中为大于基准值的元素,然后让左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
快速排序主要有三种方法:①Hoare法、②挖坑法、③前后指针


public static void quickSort(int[] array){
quickSortInternal(array,0,array.length - 1);
}
public static void quickSortInternal(int[] array,int from,int to){
if(to - from + 1 <= 1){
return;
}
int i = partition3(array,from,to);
quickSortInternal(array,from,i - 1);
quickSortInternal(array,i + 1;to);
}
public static void swap(int[] array,int i,int j){
int tmp = array[i];
array[i] = array[j];
array[j] = array[i];
}
//方法1:Hoare法
public static int partitionHoare(int[] array int from,int to){
int pivot - array[to];
int left = from;
int right = to;
while(left < right){
whlie(left < right && array[left] <= pivot){
left++;
}
swap(array,left,right);
while(left < right && array[right] >= pivot){
right--;
}
swap(array,left,right);
}
return right;
}
//方法2:挖坑法
public static int partitionDigHole(int[] array,int from,int to){
int pivot = array[to];
int left = from;
int right = to;
while(left < right){
while(left < right && array[left] <= pivot){
left++;
}
array[right] = array[left];
while(left < right && array[right] >= pivot){
right--;
}
array[left] = array[right];
}
array[left] = pivot;
return left;
}
//方法3:前后指针法
public static int partiton3(int[] array,int from,int to){
int pivot = array[to];
int b = from;
for(int d = from;d < to;d++){
if(array[d] < pivot){
swap(array,b,d);
b++;
}
}
swap(array,b,to);
return b;
}
归并排序
将已经有序的子序列合并,得到完全有序的序列,即先将每个子序列有序,再使子序列段间有序。就是先将一个序列分割成很多个只包含一个元素的序列,然后逐一进行合并排序,最后得到一个有序的序列。
注:归并排序也可以用在外部排序中


public static void mergeSort(int[] array){
mergeSortInternal(array,0,array.length);
}
public static void mergeSortInternal(int[] array,int from,int to){
if(to - from <= 1){
return;
}
int mid = from + (to - from) / 2;
mergeSortInternal(array,from,mid);
mergeSortInternal(array,mid,to);
merge(array,from,mid,to);
}
public static void merge(int[] array,int from,int mid,int to){
int size = to - from;
int[] e = new int[size];
int eIdx = 0;
int leftIdx = from;
int rightIdx = mid;
while(leftIdx < mid && right < to){
if(array[leftIdx] < array[rightIdx]){
e[eIdx] = array[leftIdx];
eIdx++;
leftIdx++;
}else{
e[eIdx] = array[right];
eIdx++;
rightIdx++:
}
}
while(left < mid){
e[eIdx] = array[leftIdx];
eIdx++;
leftIdx++;
}
while(right < to){
e[eIdx] = array[rightIdx];
eIdx++;
rightIdx++;
}
for(int i = 0;i < size;i++){
array[from + i] = e[i];
}
}
希尔排序
将待排序的数组按照一定的间隔进行分组,对每组使用插入排序算法进行排序,然后缩小间隔,再对分组进行排序,直到间隔为1为止
特点:逐渐减小间隔大小的方法有助于提高排序过程的效率,可以减少比较和交换的次数


public static void shellSort(int[] array){
if(array.length == 0){
return;
}
int gap = array.length / 2;
while(true){
for(int i = gap;i < array.length;i++){
int x = array[i];
int j;
for(j = i - gap; j >= 0 && array[j] > x;j = j - gap){
array[j + gap] = array[j];
}
array[j + gap] = x;
}
if(gap == 1){
break;
}
gap = gap / 2;
}
}
堆排序
利用二叉树建堆的一种排序算法,在排升序时,创建大堆,每次都先将堆顶元素和堆中最后一个元素进行交换后,将原来的堆顶元素拿出放入有序区间的起始位置,并且无序区间中减少一个元素。
在堆排序中,升序要建大堆,降序要建小堆,升序时的区间被划分为无序区间
在这里有一个需要注意的点,虽然说降序要建小堆(区间分为有序区间),但是其实这是办不到的,那么要是想排成降序怎么办呢?在我看来要使用Comparator接口,重新定义大小关系,将本来是小的看作是大的,本来是大的看作小的,然后再按照升序的方法进行排序


public class Heap {
// 堆排序方法
public static void heapSort(int[] arr) {
int n = arr.length;
// 构建大根堆,
// 这段代码是构建大根堆的过程,它的循环次数为n/2-1次,是因为在完全二叉树中,叶子节点不需要进行堆化操作,
// 所以只需要对非叶子节点进行堆化,而非叶子节点的数量为n/2-1个。因此,只需要循环n/2-1次即可完成大根堆的构建。
// 非叶子节点在一维数组中就是前面 n/2-1
for (int i = n / 2 - 1; i >= 0; i--) {
// 从最底层的根节点开始堆化,每次执行完成后,都找出最大值,并放在根节点位置
// 逐层往上找,循环结束后,第一个元素肯定是最大值
heapify(arr, n, i);
}
// 依次取出堆顶元素,并将余下元素继续堆化,得到有序序列
for (int i = n - 1; i >= 0; i--) {
// 第一个for循环已经找出最大值,所以先做交货,把最大值换到最后一个位置
// 把最大值交换到最后一个位置,下一次循环最后一个位置就不比较了
swap(arr, 0, i);
// 继续找出最大值,放在第一个位置
heapify(arr, i, 0);
}
}
private static void heapify(int[] arr, int heapSize, int i) {
int largest = i; // 初始化假设最大值为根节点
int left = 2 * i + 1; // 相对于索引i的左节点索引
int right = 2 * i + 2; // 相对于索引i的右节点索引
// 找到左右子节点中的最大值
if (left < heapSize && arr[left] > arr[largest]) {
// 如果有左节点,且左节点大于根节点,则记录左节点为最大值
largest = left;
}
if (right < heapSize && arr[right] > arr[largest]) {
// 如果有右节点,且右节点大于最大值,则记录右节点为最大值
largest = right;
}
// 上面两个if之后,肯定找到最大值
if (largest != i) {
// i 是根节点下标
// 如果最大值不是根节点,则交换根节点与最大值节点,
// 并递归地对最大值节点进行堆化
swap(arr, i, largest);
heapify(arr, heapSize, largest);
}
}
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 = {5, 2, 8, 3, 12, 35, 57, 1, 6};
int[] expectedArr = {1, 2, 3, 5, 6, 8, 12, 35, 57};
Heap.heapSort(arr);
System.out.println("arr = " + Arrays.toString(arr));
Assertions.assertArrayEquals(expectedArr, arr);
}
}
三个整数
题目:给出三个整数,请你设计一个程序,求出这三个数的和,乘积和平均数
输入:输入只有三个正整数a,b,c
输出:输出一行,包括三个的和,乘积,平均数
数据之间用一个空格隔开,其中平均数保留小数点后 面两位
输入:1,2,3
输出:6,6,2.00
import java.util.Scanner;
public class 三个整数 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner reader = new Scanner(System.in);
int a, b, c, sum, ji;
double ave;
a = reader.nextInt();
b = reader.nextInt();
c = reader.nextInt();
sum = a + b + c;
ji = a * b * c;
ave = sum / 3.00;
System.out.print(sum + " ");
System.out.print(ji + " ");
System.out.printf("%.2f", ave);// 浮点型数据输出,注意和c/c++不同的是double对应的数据类型是
// %f,而非%lf;
}
}
知识点
ToDo Auto-generated method stub
*Auto-generated method stub* 意思是生成方法存根,就是“自动生成方法(空函数)”。编程软件在你使用代码生成时,自动帮你加上的,告诉你这些段代码是开发工具生成的,就是一个提示,可以删除的。
automatic 自动的; generated 生成;method 方法;stub 存根;空函数;TODO 就是说在这写你自己的新代码
生成方法存根:如果某个方法,你还没有定义就开始使用,此时,可以通过你使用这种方法的情况由开发工具自动给你写好方法的最基本定义。比如说,当我们写好接口(即抽象类),然后去写接口的实现类(具体要实现的内容)。如果我们不用自动生成去手写一来麻烦,二来可能漏掉方法没有实现,会报错(因为必须实现抽象类的全部方法)。 ——————————————————————————
快速去掉:Ctrl+F 搜索这段话,Ctrl+D删除光标所在行



















