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();
}
}