简单算法练习
一、水仙花数(narcissistic number)
1.问题描述:什么是水仙花数
水仙花数
是指一个3位数,它的每个位上的数字的3次幂之和等于他本身(1^3 + 5^3 + 3^3 = 153)。
注意:水仙花数只是`自幂的一种
- 一位自幂数:独身数
2.两位自幂数:没有
3.三位自幂数:水仙花数
4.四位自幂数:四叶玫瑰数(四叶玫瑰数是指四位数各位上的数字的四次方之和等于本身的数。)
5.五位自幂数:五角星数
6.六位自幂数:六合数
7.七位自幂数:北斗七星数
8.八位自幂数:八仙数
9.九位自幂数:九九重阳数
10.十位自幂数:十全十美数
2.问题分析
根据水仙花数
的定义,判断一个数是否为“水仙花数”,最重要的是要把给出的三位数的个位、十位、百位分别拆分,并求其立方和(设为s),若s与给出的三位数相等, 三位数为“水仙花数”,反之,则不是。
3.算法设计
“水仙花数
”是指满足某一条件的三位数,根据这一信息可以确定整数的取值范围是 100〜999。对应的循环条件如下:
for(n=100;n<1000;n++)
{
//......
}
上述代码说明
- 将n除以100,得出在百位上的数字hundred;
- 将(n-i*100)整除以10(或将n先整除以10再对10求模n/10%10),得出n在十位数上的数字ten;
- 将n对10取余,得出n在个位上的数字unit
求得这三个数字的立方和是否与其本身相等,若相等,则该数为水仙花数
C语言实现
#include <stdio.h>
int main()
{
int hun, ten, unit,n;
printf("result is:")
for(n=100;n<1000;n++) /*整数的取值范围*/
{
hun = n/100;
ten = n/10%10;
unit = n%10;
if(n == hun^3 + ten^3 + unit^3) /*各位上的立方和是否与原数n相等*/
{
printf("%d ",n);
}
}
printf("\n");
return 0;
}
Java实现
/**
* @Description 水仙花数
* @Param XXX
* @Author gfl
* @Date 2021/3/9
* @Since 版本 1.1.1
*/
public class NarcissisticNumber {
public static void main(String[] args){
for (int i=100;i<1000;i++)
{
int a = i/100; //取得百位数
int b = i/10%10; //取得个位数
int c = i%10; //取得个位数
if(i == a*a*a + b*b*b + c*c*c ){
System.out.println(i + " 这是一个水仙花数");
}
}
}
}
二、冒泡排序(Bubble Sort)
是一种组基础的交换排序。
1.问题描述
将下列的无序数列,从大到小排列;
要排序数组:[10,1,35,61,89,36,55]
2.问题分析
要排序数组:[10,1,35,61,89,36,55]
@1.原理:比较两个相邻的元素,将值大的元素交换到右边
@2.思路:依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面
- 第一次比较:首先比较第一和第二个数,将小数放在前面,将大数放在后面。
- 比较第2和第3个数,将小数 放在前面,大数放在后面。
… - 如此继续,知道比较到最后的两个数,将小数放在前面,大数放在后面,重复步骤,直至全部排序完成
- 在上面一趟比较完成后,最后一个数一定是数组中最大的一个数,所以在比较第二趟的时候,最后一个数是不参加比较的。
- 在第二趟比较完成后,倒数第二个数也一定是数组中倒数第二大数,所以在第三趟的比较中,最后两个数是不参与比较的。
- 依次类推,每一趟比较次数减少依次
@3.举例
(1)要排序数组:[10,1,35,61,89,36,55]
(2)第一趟排序:
第一次排序:10和1比较,10大于1,交换位置 [1,10,35,61,89,36,55]
第二趟排序:10和35比较,10小于35,不交换位置 [1,10,35,61,89,36,55]
第三趟排序:35和61比较,35小于61,不交换位置 [1,10,35,61,89,36,55]
第四趟排序:61和89比较,61小于89,不交换位置 [1,10,35,61,89,36,55]
第五趟排序:89和36比较,89大于36,交换位置 [1,10,35,61,36,89,55]
第六趟排序:89和55比较,89大于55,交换位置 [1,10,35,61,36,55,89]
第一趟总共进行了六次比较,排序结果:[1,10,35,61,36,55,89]
(3)第二趟排序:
第一次排序:1和10比较,1小于10,不交换位置 1,10,35,61,36,55,89
第二次排序:10和35比较,10小于35,不交换位置 1,10,35,61,36,55,89
第三次排序:35和61比较,35小于61,不交换位置 1,10,35,61,36,55,89
第四次排序:61和36比较,61大于36,交换位置 1,10,35,36,61,55,89
第五次排序:61和55比较,61大于55,交换位置 1,10,35,36,55,61,89
第二趟总共进行了5次比较,排序结果:1,10,35,36,55,61,89
(4)第三趟排序:
第一次排序:1和10比较,1小于10,不交换位置 1,10,35,36,55,61,89`
第二次排序:10和35比较,10小于35,不交换位置 1,10,35,36,55,61,89
第三次排序:35和36比较,35小于36,不交换位置 1,10,35,36,55,61,89
第四次排序:36和61比较,36小于61,不交换位置 1,10,35,36,55,61,89
第三趟总共进行了4次比较,排序结果:1,10,35,36,55,61,89
到目前位置已经为有序的情形了。
算法分析
(1)由此可见:
N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次
,所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数
(2)冒泡排序的优点:
每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。如上例:第一趟比较之后,排在最后的一个数一定是最大的一个数,第二趟排序的时候,只需要比较除了最后一个数以外的其他的数,同样也能找出一个最大的数排在参与第二趟比较的数后面,第三趟比较的时候,只需要比较除了最后两个数以外的其他的数,以此类推……也就是说,没进行一趟比较,每一趟少比较一次,一定程度上减少了算法的量。
(3)时间复杂度
原始的冒泡排序是稳定的,由于该排序算法的每一轮都要遍历一遍所有的元素,轮转的次数和元素数量相当。所以时间复杂度为O(N^2)
(4)复杂度
时间复杂度: O(N^2)
空间复杂度: O(1)
稳定性:稳定
3.算法设计
/**
* @Description 冒泡排序
* @Param XXX
* @Author gfl
* @Date 2021/3/9
* @Since 版本 1.1.1
*/
public class BubbleSortTest {
public static void main(String[] args){
int[] arr = {2,21,5,45,4,888,35,10,9,4};
bubbleSort(arr);
traverse(arr);
// System.out.println(arr.length);
}
/**
* 冒泡排序
* @param arr
* */
public static void bubbleSort(int[] arr){
if(arr==null || arr.length<2){
return;
}
for (int i=0;i<arr.length-1;i++){ //(外循环,第几轮(每一轮求出一个最大值)))数组下标0-9,length=10
for (int j = 0;j<arr.length-i-1;j++){ //内循环,每一轮的第几次
if(arr[j]>arr[j+1]){ //数组arr[i]与或和一个元素之间的比较
int temp = arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp; //如果当前元素比后一个元素大的话,交换位置
}
}
}
}
/**
* 遍历数组
* @param arr
* */
public static void traverse(int[] arr){
if(arr==null || arr.length<2){
return;
}
//for形式循环
// for(int i=0;i<arr.length-1;i++){
// System.out.print(arr[i]+" ");
// }
//增强for
// for(int s:arr){
// System.out.print(s+" ");
// }
//do...while形式
// int ii = 0;
// do{
// System.out.print(arr[ii]+" ");
// ii++;
// }while(ii<arr.length);
//while形式
int g=0;
while(g<arr.length){
System.out.print(arr[g]+" ");
g++;
}
}
}
三、求1-100以内质数的和
指数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
package test;
/**
* @Description 求1-100中的质数和
* @Param XXX
* @Author gfl
* @Date 2021/3/9
* @Since 版本 1.1.1
*/
public class PrimeNumber {
public static void main(String[] args){
//首先质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数
//换言说:就是质数只有两个正因数(1和它本身);
//只要一个数(2除外)除以一个大于等于2且比自身小的数没有正因数,那么它就是一个质数;
int sum = 0;
for (int i=2;i<=100;i++){ //遍历1-100的数
Boolean isOK = true; //默认为质数
for (int j=2;j<i;j++){ //除数
if(i%j==0){
isOK = false;
}
}
if (isOK){
System.out.print(i+" ");
sum+=i;
}
}
System.out.println();
System.out.println("1~100的质数和为: "+sum);
}
}
四、二维数组的遍历
/**
* @Description 二维数组的遍历
* @Param XXX
* @Author gfl
* @Date 2021/3/9
* @Since 版本 1.1.1
*/
public class TwoDimensionalArray {
public static void main(String[] args){
// 数据类型[][]数组名称 = new 数据类型[一维数组的个数] [ 每一个一维数组的元素个数 ]
// int[][] arr = new int[2][3]; //动态初始化方式一
// int[][] arr = new int[6][]; //动态初始化方式二,一定要设置行数 arr[0]=new int[5]
int[][] arr = new int[][]{{2,5,6,8,3},{8,9,4},{36,15,8,5}};
// System.out.println("总共有: "+arr.length+" 行");
// System.out.println(arr[0].length);
// System.out.println(arr[1].length);
// System.out.println(arr[2].length);
traverse(arr);
}
public static void traverse(int[][] arr){
if(arr==null || arr.length<0){
return;
}
//for循环
// for(int i = 0;i<arr.length;i++){ //控制行数 i= 0 , 1 , 2 arr.length=3
// for (int j=0;j<arr[i].length;j++){ //一行中有多少个元素j= 0~4 , 0~2 , 0~3 arr[i].length=5,3,4
// System.out.print(arr[i][j]+" ");
// }
// System.out.println();
// }
//增强for
// for(int[] i:arr){ //行数 i=int[j]
// for (int j:i) { //每行的元素数
// System.out.print(j+"\t");
// }
// System.out.println();
// }
//while形式
// int i = 0;
// while(i<arr.length){
// for (int j = 0;j<arr[i].length;j++){
// System.out.print(arr[i][j]+"\t");
// }
// System.out.println();
// i++;
// }
//do....while形式
int i = 0;
do{
for (int j=0;j<arr[i].length;j++){
System.out.print(arr[i][j]+" ");
}
System.out.println();
i++;
}while(i<arr.length);
}
}
#include<stdio.h>是在程序编译之前要处理的内容,称为编译预处理命令。编译预处理命令还有很多,它们都以“#”开头,并且不用分号结尾,所以是c语言的程序语句。
在使用标准函数库中的输入输出函数时,编译系统要求程序提供有关的信息(例如对这些输入输出函数的声明),#include<stdio.h>的作用就是用来提供这些信息的,stdio.h是C编译系统提供的一个文件名,stdio是“standard input & output”的缩写,即有关标准输入输出的信息。
在这里的编译预处理命令称为文件包含命令,其作用是在编译之前把程序需要使用的关于系统定义的函数printf()的一些信息文件stdio.h包含进来。以“.h ”作为后缀的文件称为头文件
#include<stdlib.h>是C语言中的一个头文件,stdlib 头文件里包含了C语言的一些函数,该文件包含了的C语言标准库函数的定义。
1、意思是标准输入输出头文件。
2、用到标准输入输出函数时,就要调用这个头文件。
3、stdlib.h中,包含了C语言的一些常用且方便的库函数。
4、如动态内存相关的malloc, realloc,zalloc,calloc,free等。
参考
https://www.toutiao.com/a6593273307280179715/?iid=6593273307280179715