1、打印汉诺塔(递归法思想)的步骤:
import java.util.Scanner;
/*
汉诺塔————要求:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。
操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,
小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
在整个过程中具体所要注意的事项是:
1、有三根柱子,分别为:A(起始柱)、B(辅助柱)、C(目标柱)
2、A柱上拥有64个盘子,一次是从下到上,从大到小(即大盘在下面,小盘在上面)
3、每一次只能移动一个盘子,并且每一根柱上都得是大盘在下,小盘在上
4、最终把A柱上的盘子全部移动到C柱上
先用三个盘分析一下思路:
再分析思路之前先介绍一下递归,什么是递归?
递归算是一种解题的思想,就是把大问题化小,再把小的问题合并成最终所想要的结果。例:形如下面二叉树
9
4 5
1 3 2 3
1 2 1 1 1 2
·······
2——(1,1)
3——(1,2)
4——(1,3)
1
9——(4,5)
2——(1,1)
5——(2,3) 1
3——(1,2)
2——(1,1)
先是由大到小一层的一层分,之后又从小返回到大,整个过程就叫做递归。
具体思路:
1、先是给A柱上放三个盘子,标号为1(顶层)、2(中层)、3(底层),刚好符合从大到小;
2、再把1和2看成一个整体,因此A柱上的盘子就有两个,(1,2)(顶层)、3(底层);
3、先把(1,2)盘移到B柱上,再把3移到C柱上;
4、这下把(1,2)又分开,就成了1、2,并且都在B柱上,现在又把1移到A柱上;
5、再把2移到C柱上,再把最后一个盘子1移到C柱上,目标达成。
如果为64个盘子运用递归的思想————先把前面63个看成一个整体,64因此就被分为两个部分,接着把63又分为两个部分,前62个盘子和63,
以此类推。
具体实现步骤如下:
*/
class Test02{
public static void main(String[] args){
Scanner input=new Scanner(System.in);
System.out.print("请输入层数n:");
int n=input.nextInt();
System.out.print("请输入A、B、C:");
String str1=input.next();
String str2=input.next();
String str3=input.next();
hanNuo(n,str1,str2,str3);
}
public static void hanNuo(int n,String str1,String str2,String str3){
if(n==1){
System.out.println(str1+"->"+str3);
}else{
hanNuo(n-1,str1,str3,str2);
System.out.println(str1+"->"+str3);
hanNuo(n-1,str2,str1,str3);
//System.out.println(str2+"->"+str3);
}
}
}
2、for循环
/*
题目要求:总共打印8行,用五行分析一下解题思路吧;打印如下图形:
空格数:1 2 3 4
1 1
1 2 1 2
1 2 4 2 1 3
1 2 4 8 4 2 1 4
1 2 4 8 16 8 4 2 1 5
........
经上面的分析可得:该图形总共有5行: ————每一行由空格和具体的数字组成。
空格数是随着行数的增加而减一,因此该代码可写成:
for(int i=1;i<=5;i++){//i表示的是所打印的行数
for(int k=1;k<=5-i;k++){//k表示所打印的空格数
System.out.print(" ");
}
}
由上面可知,每一行的空格已打印,但是每一行的数字存在什么规律,以及每一行数字所要打印的个数:
1 2 3 4
1 1 1
2 1 2 1 2
3 1 2 4 2 1 3
4 1 2 4 8 4 2 1 4
5 1 2 4 8 16 8 4 2 1 5
2^0 2^1 2^2 2^3 2^4 2^3 2^2 2^1 2^0
-4 -3 -2 -1 0 1 2 3 4 x-(0) 1
x-(-1~1) 3
x-(-2~2) 5
x-(-3~3) 7
x-(-4~4) 9
........
因此由上面分析得每一行所打印数字的个数为1-i ~ i-1
并且每一行随打印的数值都是2的次幂,次幂的规律而是从0~4~0
第五行———— 所对应的坐标的绝对值与行数差了一个1
第四行———— 所对应的坐标的绝对值与行数差了一个1
第三行———— 所对应的坐标的绝对值与行数差了一个1
.......以此类推
因此在坐标的绝对值的基础上再加一个1与行数相等,正它们的差刚好是所对应每一行所要打印的第一个数值的次幂数,即2^(坐标的绝对值的基础上再加一个1与行数的差)
------因此代码可写为:
for(int m=1-i;m<=i-1;m++){
System.out.print(Math.abs(m)+1);
}
[注:再下来就是格式的要求——由于每一行所打印的最高位数值所占的大小为三个空格大小,因此就有输出的格式要求——————代码就可改为:
System.out.printf("%3.0f",Math.pow(2,i-1-Math.abs(k)));
特别提醒:为什么格式输出是%3.0f,因为Math.pow()——所执行的结果直接为double型,所以为%f,至于4,就是所输出的值所占的空格大小。
]
最后如果改成输入多少行就打印多少行,则只需改代码中的数字五变成一个变量。
*/
class Demo16{
public static void main(String[] args){
for(int i=1;i<=5;i++){//i表示的是行数
for(int j=1;j<=5-i;j++){
System.out.print(" ");
}
for(int k=1-i;k<=i-1;k++){
System.out.printf("%4.0f",Math.pow(2,i-1-Math.abs(k)));
}
System.out.println();
}
}
}
3、while循环
import java.util.Scanner;
/*
当输入若干个数字时,在内存中的调用机制————例:
输入的数字为:1 2 3 4 5 6 0
nextDouble();———下一个为1
1
nextDouble();———下一个为2
2
nextDouble();———下一个为3
3
nextDouble();———下一个为4
4
nextDouble();———下一个为5
5
nextDouble();———下一个为6
6
nextDouble();———下一个为0
0————表示的是循环结束的条件
对于当输入的数字存放在所定义的num中时————int num=nextInt();
nextInt();表示的是存放下一个数字
当用户输入入若干个数字时,这些数字先存放在一个临时存储区,等待被调用
因此对于While循环来说——形如:
System.out.print("Enter an integer,the input ends if it is 0:");
while(true){
double num=input.nextDouble();
if(num==0){
break;
}
}
运行过程如下:
先是num=1; 与0做判断,如果等于0,跳出循环,否则num=2;再判断,以此类推。
*/
class Demo11{
public static void main(String[] args){
Scanner input=new Scanner(System.in);
int pos=0;//存放的是大于0的数
int neg=0;//存放的是小于0得数
double sum=0;//求和
System.out.print("Enter an integer,the input ends if it is 0:");
while(true){
double num=input.nextDouble();
if(num!=0){
sum+=num;
if(num>0){
pos++;
}else{
neg++;
}
}else{
break;
}
}
System.out.println("The number of positives is "+pos);
System.out.println("The number of negatives is "+neg);
System.out.println("The total is "+sum);
System.out.println("The average is "+sum/(pos+neg));
}
}
import java.util.Scanner;
/*
题目的要求是:求一元二次方程的根
第一步确定一元二次方程的表达式:a*x^2+b*x+c=0
第二步确定一元二次方程跟的情况
第三步:判断,判断的条件为——b*b-4*a*c
第四步:如果判断的条件大于0,有两个根
小于0,无实数解
等于0,有两个相同的解
第五步:编写代码
*/
class Demo01{
public static void main(String[] args){
Scanner input=new Scanner(System.in);
System.out.print("Enter a, b, c:");//输入一元二次方程的三个参数
double a=input.nextDouble();
double b=input.nextDouble();
double c=input.nextDouble();
double x,y;//两个未知变量
/*
if-else语句
*/
if((b*b-4*a*c)>0){
x=(-b+Math.pow((b*b-4*a*c),0.5))/2*a;
y=(-b-Math.pow((b*b-4*a*c),0.5))/2*a;
System.out.println("x=" + x + " , " + "y=" + y);
} else if((b*b-4*a*c)==0){
x=(-b+Math.pow((b*b-4*a*c),0.5))/2*a;
y=x;
System.out.println("x=" + x + " , " + "y=" + y);
}else{
System.out.println("无实数解");
}
}
}
import java.util.Scanner;
/*
题目要求:采拳游戏
石头 0 剪刀 1 布 2
系统产生的随机数——————调用数学函数Math.random();该函数产生的是0到1.0的随机数,而且默认的是double型
因此必须得强制进行数据类型的转化
第一步:确定用户赢的可能————用户赢
用户0 系统1
用户1 系统2
用户2 系统0
第二步:如果用户与系统相同——————平手
第三步:其余系统赢
第四步:编写代码
*/
class Demo06{
public static void main(String[] args){
Scanner input=new Scanner(System.in);
//系统所产生的随机数
int count=0;
while(true){
System.out.print("scissor(0) ,rock(1) ,paper(2):");
int num1=input.nextInt();
int num2=(int)(Math.random()*3);
if(num1<num2 || num1==2&&num2==0){
System.out.println("你赢了");
count++;
//System.out.println(count);
if(count==2){
break;
}
}else{
System.out.println("你输了");
}
}
}
}
import java.util.Scanner;
/*
题目要求:构造一个函数,并调用该函数打印如下图案:
1 2 3
1 1
2 1 2
3 2 1 3
4 3 2 1 4
···· 1 ·
·
·
n
第一步:提示用户输入一个n ·
第二步:确定构造函数所要执行什么样的功能,根据题目的要求——
可得,该题目所需要的构造函数做执行的功能是上述图案
第三步:先打印前四行,由图案可知每一行是由空格和数值所组成,并且
每一行的空格数随着行的增加而减少,并且每一行的第一个数字一行数一样
因此:
for(int i=1;i<=n;i++){
for(int j=1;j<=n-i;j++){
System.out.print(" ");
}
for(int k=i;k>=1;k--){
System.out.print(k+" ");
}
System.out.println();
}
*/
class Demo03{
public static void main(String[] args){
Scanner input=new Scanner(System.in);
System.out.print("请用户输入一个数num:");
int num=input.nextInt();
displayPattern(num);
}
public static void displayPattern(int n){
for(int i=1;i<=n;i++){
for(int j=1;j<=n-i;j++){
System.out.print(" ");
}
for(int k=i;k>=1;k--){
System.out.print(k+" ");
}
System.out.println();
}
}
}
4、斐波那契数列(迭代思想)
import java.util.Scanner;
class Test05{
/*
用迭代的思想打印斐波那契数列
首先明确斐波那契数列是形如怎样的数列?
1 1 2 3 5 8 13 21 ···
该数列具有怎样的规律:
从该数列的第三个数值开始,下一个位置上的数值是前两个数值之和
迭代思想具体体现在哪儿?
比如:先定义三个变量——a、b、c
a——用来存放该数列的第一个数值
b——用来存放该数列的第二个数值
c——用来存放前两个数值之和
这样才能出现前三个数值,那后面的该怎样办?明知道是一个循环,那么该循环体是什么?
已经定义了三个变量,并已经知道三个变量的含义
因此循环体——在进行第四个数值打印时——将:a=b;b=c;c=a+b;
所以这种思想就是迭代思想——代码如下:
*/
public static void main(String[] args){
Scanner input=new Scanner(System.in);
System.out.print("请输入想打印斐波那契数列的个数n:");
int n=input.nextInt();
int count=0;//记录个数
int a=1;
System.out.print(a+" ");
count++;
int b=1;
System.out.print(b+" ");
count++;
int c;
while(true){
c=a+b;//得出斐波那契数列中的数值
System.out.print(c+" ");
count++;
/*
迭代思想
*/
a=b;
b=c;
/*
终止条件
*/
if(count==n){
break;
}
}
}
}
5、数组的查找(主要二分法查找)
import java.util.Scanner;
/*
所谓查找,不明思议就是在一组数据中查找某一个值(大多情况下就是定义一个数组,在给定某一个值,进行查找),
而且查找的结果就只有两种,一、true;二、false
具体查找的方法都有哪些?——一般就是将给定的一组数据,从第一个遍历到所要查找的数值之后结束
并打印自己所查找的结果,对于初学者估计有很大的帮助,便于理解。
但是该方法的规模呈线性增长,当一组数据足够多时,岂不是规模越大,时间复杂度就越大
二——接下来这一种算法就是二分法:
二分法应该不陌生吧,不明思议就是对半查找,但是二分法查找是有一定的前提:就是该数据必须呈一种
升序或者降序
例如:在下面的一组数据中查找7
编号: 0 1 2 3 4 5 6
1 3 5 7 9 12 34 该数据总共为6个
查找的第一步:首先把该数据分成两部分——
0 1 2
第一步分为:1 3 5
3 4 5 6
第二部分为:7 9 12 34
查找的第二部:比较所要查的数值(7)与(该组数据的最小下标与最大下标之和再整除2的值)
查找的第三步:如果大于在第二部分里面在找,如果小于就在第一部分里面查找;
查找的第四部:7大于该值,因此在第二部分,所以再把第二部分数据分为两个部分——
3 4
第一部分:7 9
5 6
第二部分:12 34
查找的第五步:重复第二步,第三步
查找的第六步:最终找到在下标为3处所对应的值是7
总结:二分查找虽然过程能麻烦一点,但是规模较小于第一种方法,该方法的时间复杂度为logn
等其它查找方法
在查找的整个过程中会遇到,排序问题:我先介绍一下冒泡排序:
例:给定一组数据要求为升序:
1 3 2 7 4 总共为6个数字
具体的排序思路如下:
第一步:0 1 2 3 4
1 3 2 7 4 先是进行0和1进行比较:1小于3,则不动,再进行3和2比较,3大于2,3与2交换位置
以此类推,因此第一次所得结果为:1 2 3 4 7,结束
*/
class Test03{
public static void main(String[] args){
Scanner input=new Scanner(System.in);
System.out.print("请输入一串数字:");
int[] arr=new int[10];
int count=0;
int temp=1;
while(true){
arr[count++]=input.nextInt();
if(count==10){
break;
}
}
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
System.out.println();
/*
冒泡排序
*/
for(int i=1;i<10;i++){
for(int j=0;j<9;j++){
if(arr[j]>arr[j+1]){
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
System.out.println();
int index=-1;//存放下标的
int min=0;//存放小的下标
int max=arr.length-1;//存放大的下标
int mid=(min+max)/2;//中间
System.out.print("Enter a num:");
int num=input.nextInt();
while(true){
if(num>arr[mid]){
min=mid+1;
mid=(min+max)/2;
}else if(num<arr[mid]){
max=mid-1;
mid=(min+max)/2;
}else{
index=mid;
System.out.println(index);
break;
}
if(min>max){
System.out.println(index);
break;
}
}
}
}
六、数组的排序问题
class Test02{
public static void main(String[] args){
int[] arr1=new int[]{1,3,2,7,4,6,8,5,9};
int[] arr2=new int[]{1,3,2,7,4,6,8,5,9};
int[] arr3=new int[]{1,3,2,7,4,6,8,5,9};
int[] arr4=new int[]{1,3,2,7,4,6,8,5,9};
int temp=0;
/*
选择排序————具体通过一组数据来说明什么是选择排序?定义一个一位数组
a[]={1,3,2,7,4,6,8,5,9};
要求是:按升序排列
数组的下标: 0 1 2 3 4 5 6 7 8
1 3 2 7 4 6 8 5 9
首先先具体分析一下整个选择的过程:
第一次:
数组的下标: 0 1 2 3 4 5 6 7 8
1 3 2 7 4 6 8 5 9
首先是数组中a[0]与a[1]先比较,如果大于,两个数字交换,否则进行a[0]与a[2]比较
,如果大于,两个数交换,否则继续,以此类推,因此第一次比较的结果为:
1 3 2 7 4 6 8 5 9
第二次:
首先是数组中a[1]与a[2]比较,如果大于,两个数交换,否则进行a[1]与a[3]比较,
如果大于,两个数进行交换,否则继续,以此类推,因此第三次比较的结果为:
1 2 3 7 4 6 8 5 9
第三次:1 2 3 7 4 6 8 5 9
第四次:1 2 3 4 7 6 8 5 9
第五次:1 2 3 4 5 7 8 6 9
第六次:1 2 3 4 5 6 8 7 9
第七次:1 2 3 4 5 6 7 8 9
第八次:1 2 3 4 5 6 7 8 9
整个过程就是选择排序。
*/
for(int i=0;i<arr1.length-1;i++){
for(int j=i+1;j<arr1.length;j++){
if(arr1[i]>arr1[j]){
temp=arr1[i];
arr1[i]=arr1[j];
arr1[j]=temp;
}
}
}
System.out.print("选择排序:");
for(int i=0;i<arr1.length;i++){
System.out.print(arr1[i]+" ");
}
System.out.println();
maoPao(arr2);
youHua(arr3);
chaRu(arr4);
}
/*
冒泡排序————例:给定一组数据——要求升序
2 4 3 8 6 9 7
第一次:
第一步:首先判断给定数据的前两个数值:2和4的大小,如果前者大于后者,则前者与后者交换位置,否则,不用
2 4 3 8 6 9 7
第二步:在第一步的基础上判断第二个和第三个数值的大小,如果前者大于后者,则前者与后者交换位置,否则,不用
2 3 4 8 6 9 7
第三步:2 3 4 8 6 9 7
第四步:2 3 4 6 8 9 7
以此类推
因此第一步所得的结果为:2 3 4 6 8 7 9
第二次所得结果:2 3 4 6 7 8 9
以此类推
最终结果为:2 3 4 6 7 8 9
以上就是冒泡排序的这个过程
*/
public static void maoPao(int[] arr){
int temp=0;
for(int i=0;i<arr.length-1;i++){
for(int j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
System.out.print("冒泡排序:");
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
System.out.println();
}
/*
冒泡排序的优化——例:给定一组数据——要求升序
2 4 3 8 6 9 7
由上面可知,如果这组数据中最大的数字位于该数据的首位,岂不是得比较该数据长度-1次
而且在每一次比较的时候都得需要交换两个数值,因此为了避免多次交换,引入一个存放数值的变量temp;
具体思路以及解题过程如下:
第一次:2 3 4 6 8 7 9
第一步:先把该数据的第一个元素存放到temp中,temp=2;接着再判断temp的值与该数据第二个元素的大小
,如果大于,则前移,如果小于,把temp赋值给该数值的前一位,再把该数据中比temp值大的数赋值给temp,
以此类推
第二次:2 3 4 6 7 8 9
*/
public static void youHua(int[] arr){
int temp=0;
for(int i=0;i<arr.length-1;i++){
temp=arr[0];
for(int j=0;j<arr.length-i-1;j++){
if(temp>arr[j+1]){
arr[j]=arr[j+1];
}
else{
arr[j]=temp;
temp=arr[j+1];
}
}
arr[arr.length-i-1]=temp;
}
System.out.print("冒泡排序的优化:");
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
System.out.println();
}
/*
插入排序——例:给定一组数据——要求升序
2 4 3 8 6 9 7
插入排序的本质也是交换两个数值,插入排序,首先是从一组数据中第二个元素开始,之后每一从后面去一个
元素,放到前面一个合适的位置,因此称之为插入。
第一步:先是从一组数据中的第二个元素开始进行;
第二步:开始第二个元素与第一个元素比较,如果前者大于后者,则前者与后者交换位置,否则,不用
因此所得结果:2 4 3 8 6 9 7
以此类推
第三步:2 3 4 8 6 9 7
第四步:2 3 4 8 6 9 7
第五步:2 3 4 6 8 9 7
第六步:2 3 4 6 8 9 7
第七步:2 3 4 6 8 7 9
因此以上就是插入排序的整个过程
*/
public static void chaRu(int[] arr){
int temp=0;
for(int i=0;i<arr.length-1;i++){
for(int j=i+1;j>=1;j--){
if(arr[j]<arr[j-1]){
temp=arr[j];
arr[j]=arr[j-1];
arr[j-1]=temp;
}
}
}
System.out.print("插入排序:");
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
System.out.println();
}
}
//计数排序
import java.util.Scanner;
class Demo01_02{
public static void main(String[] args){
Scanner input=new Scanner(System.in);
System.out.print("Enter a nums:");
int[] arr=new int[0];
while(true){
int num=input.nextInt();
if(num==0){
break;
}
arr=copyOf(arr);
arr[arr.length-1]=num;
}
/*
计数排序——1、计数排序就是首先申请一篇与给定数据的最大值与最小值的差加一同大小的空间
2、然后遍历给定的数据,把一个数据存放在与之该数据的值减去最小值得到的结果,
然后把该结果与所申请空间的下标对应起来,即该下标所对应的值加一
3、因为所申请的数组大小并没有赋值,因此,该下标所对应的值都为0
下面通过一组数据说明问题:
给定的数据:1 2 5 3 4 3 -2 -2 2
1、首先先确定该数组的最大值max与最小值min——max=5;min=-2
2、确定所要申请数组的空间大小:max-min+1=8
3、标记新数组的下标:
0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7
4、遍历该数组:
1 2 5 3 4 3 -2 -2 2
第一个元素:1——所对应的下标为:1-min=3
因此在第三步中对应下标3中所存的数字加一
第二个元素:2——所对应的下标为:2-min=4
因此在第三步中对应下标4中所存的数字加一
以此类推
*/
int min=arr[0];
int max=0;
int offest=0;
for(int i=0;i<arr.length;i++){
if(arr[i]>max){
max=arr[i];
}
if(arr[i]<min){
min=arr[i];
}
}
int[] newArr=new int[max-min+1];
for(int i=0;i<arr.length;i++){
newArr[arr[i]-min]++;
}
/*
输出语句
*/
show(arr,newArr);
}
public static int[] copyOf(int[] arr){
int[] newArr=new int[arr.length+1];
for(int i=0;i<arr.length;i++){
newArr[i]=arr[i];
}
return newArr;
}
public static void show(int[] arr,int[] newArr){
int min=arr[0];
for(int i=0;i<arr.length;i++){
if(arr[i]<min){
min=arr[i];
}
}
for(int i=0;i<newArr.length;i++){
for(int j=1;j<=newArr[i];j++){
System.out.print((i+min)+" ");
}
}
System.out.println();
}
}