自訂資料型態及資料結構

目的

Java 的原生基本資料型態共有 8 個,比如 int、short….。當我們想要建立一個叫 Student 的資料型態,裏面有名字、英文成績、數學成績,此時就必需把這三項型態組合成一個自訂的資料型態。

語法

自訂的資料型態在 C 語言使用 struct 指令,在 Java 裏直接改成 class。請注意如下 class Student 是寫在 public class Test 之外,也就是外部類別。

要產生一個新的 Student,使用 new 關鍵字。這跟 C 語言調用 malloc() 函數一樣,都是跟系統要求某一區塊的記憶體。產生出來的 s1 稱為物件 (Object)。要存取 s1 裏的 name、eng 就直接在 s1後面加上「.」。 「.」 就是「的」, 比如 s1.name 即「s1 的 name」。

public class Test {
    public static void main(String[] args){
        Student s1=new Student();
        s1.name="Thomas";
        s1.eng=100;
        s1.math=80;
    }
}
class Student{
    String name;
    int eng, math;
}

上面的代碼可以簡略下一個定論 : 什麼是類別 (class) ? 類別就是一個自訂的資料型態。

預設值

產生出來的 s1,裏面的變數會被系統自動初始化, String 初始化為 null,int 初始化為 0,小數初始化為 0.0。

public class Test {
    public static void main(String[] args){
        Student s1=new Student();
        System.out.printf("namd : %s, eng : %d, math : %d\n", s1.name, s1.eng, s1.math);
    }
}
class Student{
    String name;
    int eng, math;
}
結果 : 
namd : null, eng : 0, math : 0

單向連結

陣列的限制

使用陣列時,必需先宣告,如

int[] array=new int[10];

a 是一個長度為10 個元素的陣列,一經宣告長度就不能改變。重點在於一開始我們怎麼知道是要宣告為 10 或 100 呢?

比如要記錄每個客人消費的金額,打從一開門,到底是要宣告有幾個客人? 因為無法預測,所以無法定長度。

解決方案

上述的問題很明顯使用陣列是無法解決,所以必需另想辦法。下圖即是資料結構課程裏頂頂有名的單向連結。先產生一個 root 及 index,並產生一個節點 @f1。

當需要記錄某數字比如50,就將 50 放入 @f1中,然後再產生一個節點 @f2,此 @f2 記錄在 @f1 的 next 變數中。當要再次記錄另一個數字,就放入最後的節點,然後再產生一個新的節點 stand by。

如此就可以無限的擴充長度,只要記憶體不要爆掉就好。就算記憶體爆了,還是可以寫個網路連結的方法,將別台電腦的記憶體納入自已來使用。

singlelink

程式代碼

上述的每一個節點都有二個值,一個是記錄數字用的,另一個是記錄下一個節點。所以節點的自訂資料格式為

class Node{
    int d;
    Node next;
}

上面的 Node next,是說 class 裏有一個變數,而這個變數是指向一個新的 Node ,完整代碼如下。

public class SingleLink {
    public static void main(String[] args){
        Node root=new Node();
        Node index=root;
        Scanner in=new Scanner(System.in);
        int x=0;
        while(true){
            System.out.print("請輸入數字(-1離開) : ");
            x=in.nextInt();
            if(x==-1)break;
            index.d=x;
            index.next=new Node();
            index=index.next;
        }
        index=root;
        while(index.next!=null){
            System.out.printf("%d ", index.d);
            index=index.next;
        }
        System.out.println();
    }
}
class Node{
    int d;
    Node next;
}

結果 : 
請輸入數字(-1離開) : 10
請輸入數字(-1離開) : 50
請輸入數字(-1離開) : 60
請輸入數字(-1離開) : 70
請輸入數字(-1離開) : 80
請輸入數字(-1離開) : 90
請輸入數字(-1離開) : -1
10 50 60 70 80 90

雙向連結

單向連結的缺點

前一章所提及的單向連結可以無限的擴充長度,只要記憶體不要爆掉就好。但有一個缺失就是無法反向列印。

解決方案

單向連結無法反向列印,其實是可以用其他演算法解決。但這演算法實在是太耗費時間,所以才會有如下的結構。下面每個節點又多一個記錄前一個節點的變數 prev,如果就可以正反向列印。

doublelink

代碼

public class DoubleLink {
    public static void main(String[] args){
        Node root=new Node();
        Node index=root;
        Scanner in=new Scanner(System.in);
        int x=0;
        while(true){
            System.out.print("請輸入數字(-1離開) : ");
            x=in.nextInt();
            if(x==-1)break;
            index.d=x;
            index.next=new Node();
            index.next.prev=index;
            index=index.next;
        }
        //正向列印
        index=root;
        System.out.println("正向列印......");
        while(index.next!=null){
            System.out.printf("%d ", index.d);
            index=index.next;
        }
        System.out.println();
        //反向列印
        index=root;
        while(index.next!=null)index=index.next;
        System.out.println("反向列印......");
        while(index.prev!=null){
            System.out.printf("%d ", index.prev.d);
            index=index.prev;
        }
        System.out.println();
    }
}
class Node{
    Node prev;
    int d;
    Node next;
}
結果 : 
請輸入數字(-1離開) : 10
請輸入數字(-1離開) : 20
請輸入數字(-1離開) : 30
請輸入數字(-1離開) : 40
請輸入數字(-1離開) : 50
請輸入數字(-1離開) : -1
正向列印......
10 20 30 40 50 
反向列印......
50 40 30 20 10

二元樹排序法

規則

二元樹排序(Binary Sort)又有人稱為黑紅樹,它是所有高科技的開端,沒有這個演算法就不會有現今這個世界。其規則如下

1. 左邊小, 右邊大
2. 左中右, 中間取值

架構圖

binarytree

程式架構

下面的代碼依序執行如下動作

1. 產生n 個元素的陣列
2. 將亂數填入陣列中
3. 將陣列列印出來
4. 建立二元樹
5. 排序
6. 列印排序後的陣印

package binarytree;
public class BinaryTree {
    static int[]array;
    static int index=0;
    public static void main(String[] args) {
        //產生陣列並填入亂數
        int n=10;
        array=new int[n];
        for (int i=0;i<array.length;i++){
            array[i]=(int)(Math.random()*10000);
        }
        
        //列印未排序的陣列
        printData(array);
        
        //建立二元樹
        Node root=null;
        for (int i=0;i<array.length;i++){
            root=bt(root, array[i]);
        }
        
        //排序
        sort(root);
        
        //列印排完序後的陣列
        printData(array);
    }
    public static void printData(int[] array){
        //todo
    }

    //bt : buildTree的縮寫
    public static Node bt(Node node, int value){
        //todo
    }
    public static void sort(Node node){
        //todo
    }
}

//節點資料結構
class Node{
    Node left;
    Node right;
    int value;
    public Node(int value){
        this.value=value;
    }
}

完整代碼

package binarytree;
public class BinaryTree {
    static int[]array;
    static int index=0;
    public static void main(String[] args) {
        /*
        1. n=10;
        2. 產生陣列 array
        3. 填入亂數
        4. 列印
        5. 建立二元樹
        6. 排序
        7. 列印
        */
                
        int n=10;
        array=new int[n];
        for (int i=0;i<array.length;i++){
            array[i]=(int)(Math.random()*10000);
        }
        printData(array);
        Node root=null;
        for (int i=0;i<array.length;i++){
            root=bt(root, array[i]);
        }
        sort(root);
        printData(array);
    }
    public static void printData(int[] array){
        for (int i=0;i<array.length;i++){
            System.out.printf("%d ", array[i]);
        }
        System.out.println();
    }
    public static Node bt(Node node, int value){
        //進入點沒東西, 就產生節點
        if (node==null)node=new Node(value);
        //否則就判斷是往左邊走, 或往右邊走
        else if (value<node.value)node.left=bt(node.left, value);
        else node.right=bt(node.right, value);
        return node;
    }
    public static void sort(Node node){
        //左中右, 中間取值
        
        //底下為往左邊走
        if (node.left!=null)sort(node.left);
        
        //中間取值
        array[index++]=node.value;
        
        //接下來, 往右邊走
        if (node.right!=null)sort(node.right);
    }
}
class Node{
    Node left;
    Node right;
    int value;
    public Node(int value){
        this.value=value;
    }
}

結果 : 
29 154 252 349 411 447 462 543 734 982

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *