20172303 2018-2019-1 《程序設計與數據結構》實驗一報告

20172303 2018-2019-1 《程序設計與數據結構》實驗一報告

  • 課程:《程序設計與數據結構》
  • 班級: 1723
  • 姓名: 範雯琪
  • 學號:20172303
  • 實驗教師:王志強
  • 助教:張師瑜/張之睿
  • 實驗日期:2018年9月26日
  • 必修/選修: 必修

實驗內容

本次實驗分爲鏈表練習和數組練習兩部分,是對咱們從開學到如今學過的數據結構的一個練習及應用。雖然藍墨雲上分了五個節點,但其實是用鏈表和數組的方式分別進行如下三個節點的步驟。php

節點一

  • 經過鍵盤輸入一些整數,創建一個鏈表。
  • 打印全部鏈表元素, 並輸出元素的總數。
  • 在程序中,請用一個特殊變量名來紀錄元素的總數。

節點二

  • 從磁盤讀取一個文件,這個文件有兩個數字。
  • 在實驗一的基礎上實現節點插入、刪除、輸出操做:
    • 從文件中讀入數字1,插入到鏈表第5位,並打印全部數字和元素的總數。
    • 從文件中讀入數字2,插入到鏈表第0位,並打印全部數字和元素的總數。
    • 從鏈表中刪除剛纔的數字1,並打印全部數字和元素的總數。

節點三

  • 使用冒泡排序法或者選擇排序法根據數值大小對鏈表進行排序(學號是單數,選擇冒泡排序,不然選擇選擇排序)
  • 在排序的每個輪次中,打印元素的總數,和目前鏈表的全部元素。

實驗過程及結果

實驗一

實驗一的要求是完成上述節點一所提到的內容。html

1.鏈表的使用

  • 本學期至今咱們學過的使用鏈表實現的有棧和隊列兩種邏輯結構,因爲題目提到的要求是要將輸入的元素打印出來,所以要存儲輸入的元素的順序,因此應該選擇元素處理方式爲FIFO(先進先出)的隊列。
  • 我選擇了第五章學習的LinkedQueue類來實現,主要使用了LinkedQueue類的構造方法、enqueue方法size()方法toString()方法

2.實現將輸入的字符串轉換成鏈表

  • 這裏我使用了兩種方法來實現,一種使用了StringTokenizer類,另外一種使用了String類的split方法
  • StringTokenizer類
    • 我本來參照着之前的PP3.2中的代碼來實現的。
    StringTokenizer tokenizer = new StringTokenizer(str);
        while (tokenizer.hasMoreTokens()){
            String transfer = tokenizer.nextToken();
            for (int i = 0;i < transfer.length();i++){
                queue.enqueue(transfer.charAt(i));
            }
        }
    • 可是在測試的時候發現它變成了一個數字一個節點,即便我輸入空格來進行劃分,輸出結果也是同樣的。
    • 在使用了DeBug以後發現是for循環的條件出了問題,同時,由於我以前使用的是charAt()方法,因此致使了輸出以後是一個數字一個節點的問題。
    StringTokenizer tokenizer = new StringTokenizer(str);
        while (tokenizer.hasMoreTokens()){
            String transfer = tokenizer.nextToken();
            for (int i = 1;i < transfer.length();i++){
                queue.enqueue(transfer);
            }
        }
  • split方法
    • 這個方法相對來講比較簡單,JDK中的介紹是這樣的:
    • 它其實就是按照指定的正則表達式(這裏使用的空格)將輸入的內容進行劃分並放到一個字符串數組中,以後再經過一個循環將數組轉化成鏈表便可。
    String[] transfer = str.split(" ");
    for (int i = 0; i < transfer.length;i++){
         queue.enqueue(transfer[i]);
    }

3.測試結果

實驗二

實驗二的要求是完成上述節點二所提到的內容。java

1.實現文件的讀取

  • 文件的讀取和寫入咱們在上個學期已經學習並使用過,這回應該是讓咱們進行一個複習,此處附上學期學習IO流的記錄博客
  • 我使用的是字節緩衝流的方式。
//讀取文件
BufferedInputStream in = new BufferedInputStream(new FileInputStream("E:\\java\\point2.txt"));
//一次性取多少字節
byte[] bytes = new byte[2048];
//接受讀取的內容(n就表明的相關數據,只不過是數字的形式)
int n = -1;
String a = null;
//循環取出數據
while ((n = in.read(bytes,0,bytes.length)) != -1) {
    //轉換成字符串
    a = new String(bytes,0,n,"GBK");
}

2.實現插入和刪除的方法

  • 以前在學習鏈表的時候,老師曾經佈置過做業活動讓咱們來實現鏈表的插入和刪除,這裏的實現其實與當初的實現是大同小異的。因此要作的就是修改以前的LinkedQueue類,在其中加入三個方法便可。
  • 在開頭插入
public void addFirst(T element){
        LinearNode<T> node = new LinearNode<T>((T) element);
        if (head == null) {
            head = node;
            tail = node;
        }
        else {
            node.setNext(head);
            head = node;
        }
        count++;
    }
  • 在中間插入
public void addMiddle(int index,T element){
        LinearNode<T> node = new LinearNode<>(element);
        LinearNode<T> current = head;
        int j = 0;
        while (current != null && j < index - 2){//使指針指向index-1的位置
            current = current.getNext();
            j ++;
        }
        node.setNext(current.getNext());
        current.setNext(node);
        count++;
    }
  • 刪除
public void Delete(int index){
        LinearNode<T> current = head;
        LinearNode<T> temp = head;
        if (index == 0){
            head = head.getNext();
        }
        else {
            for (int i = 0;i < index - 1;i++){
                temp = current;
                current = current.getNext();
            }
            temp.setNext(current.getNext());
        }
        count--;
    }

3.測試結果

實驗三

實驗三的要求是完成上述節點三所提到的內容。node

1.冒泡排序

  • 原理:比較兩個相鄰的元素,將值大的元素交換至右端。
  • 優勢:每進行一趟排序,就會少比較一次,由於每進行一趟排序都會找出一個較大值。
  • 時間複雜度:若是這個排序原本就是正序的,那麼冒泡排序的時間複雜度就是O(n),可是顯然在顯示生活中這種狀況是不多見的。若是很不幸咱們的數據是反序的,則須要進行n-1趟排序。每趟排序要進行n-i次比較(1≤i≤n-1),且每次比較都必須移動記錄三次來達到交換記錄位置。在這種狀況下,比較和移動次數均達到最大值:
  • 因此冒泡排序的最壞時間複雜度爲O(n^2)。
  • 所以,冒泡排序的平均時間複雜度爲O(n^2),其實就是說:當數據越接近正序時,冒泡排序性能越好。
public void Sort(){
        LinearNode<T> node = head,current = null;
        if (head == null || head.getNext() == null){
            return;
        }
        while (node.getNext() != current){
            while (node.getNext() != current){
                if (Integer.parseInt(String.valueOf(node.getElement()))  > (Integer.parseInt(String.valueOf(node.getNext().getElement())))){
                    T temp = node.getElement();
                    node.setElement(node.getNext().getElement());
                    node.getNext().setElement(temp);
                }
                node = node.getNext();
            }
            current = node;
            node = head;
            LinearNode<T> temp = head;
            String str = "";
            int i = 0;
            while (temp != null){
                str += temp.getElement() + " ";
                temp = temp.getNext();
                i++;
            }
            System.out.println(str);
            System.out.println("元素總數爲: " + count);
        }
        return;
    }

2.測試結果

實驗四

實驗四的要求是完成上述節點一和節點二所提到的內容。git

1.數組的使用

  • 由於書上所給出的用數組實現的隊列是一個循環隊列,放在這裏不是很好用,因此我又從新寫了一個ArrayQueue類來完成接下來的實驗,由於時間關係我只寫了實驗中要使用的方法,而一些Queue常規的方法好比dequeue並無實現。
  • 和實驗一同樣,要使用了LinkedQueue類的構造方法、enqueue方法size()方法toString()方法,在編寫這些方法中一些其餘必要的方法好比isEmpty()、expandCapacity()等也都進行了實現。
  • 因爲ArrayQueue類中的方法不少,此處就再也不一一列出,放出碼雲連接

2.實現插入和刪除的功能

  • 其餘步驟與實驗1、實驗二相同,在此就再也不贅述。
  • 插入
    • 數組的插入相比鏈表的插入要簡單一些,由於不須要考慮插入元素所在的位置,由於數組的存儲地址都是連續的,所以不懼怕會存在像鏈表同樣丟失某個節點的狀況。
    public void insert(int index,int element){
        if (index != 0){
            int i;
            for (i = count + 1; i >= index - 1; i--){
                queue[i] = queue[i - 1];
            }
            queue[i + 1] = element;
        }
        else {
            for (int i = count + 1;i > 0;i--){
                queue[i] = queue[i - 1];
            }
            queue[0] = element;
        }
        count++;
    }
  • 刪除
    • 數組的刪除操做更爲簡單,只要將數組後一個的值賦給要刪除的位置便可。
    public void delete(int index){
        for (int i = index;i < count;i++){
            queue[i] = queue[i + 1];
        }
        count--;
    }

3.測試結果


實驗五

1.插入排序

  • 插入排序是上學期學過的兩種排序之一,當初課本上實現插入排序也是經過數組實現的,因此這裏插入排序的實現也比較簡單。
public void Sort(){
        for (int i = 0;i < count;i++){
            int k = i;
            //找出最小值
            for (int j = i + 1;j < count;j++){
                if (queue[k] > queue[j]){
                    k = j;
                }
            }
            //進行排序
            if (k > i){
                int temp = queue[i];
                queue[i] = queue[k];
                queue[k] = temp;
            }
            int b = i + 1;
            System.out.println("第" + b + "次排序後的數組爲: ");
            for (int a = 0;a < count;a++){
                String str = "";
                str += queue[a] + " ";
                System.out.print(str);
            }
            System.out.println();
            System.out.println("元素總數爲: " + count);
        }
    }

2.測試結果


實驗過程當中遇到的問題和解決過程

  • 問題1:splitStringTokenizer都能實現截取字符串的功能,那麼在實際狀況中應該如何選擇呢?
  • 問題1解決方法:查找了不少資料發現都說StringTokenizer要比split性能好.
  • 你們在對比時都是將subStringsplitStringTokenizer三者進行比較的,可能由於不一樣的人測試的方法不一樣,有時候subStringsplit效率高可是有時候split又更勝一籌,可是StringTokenizer確定都是耗費時間最短的。不過當要截取的字符串不是很長時三者能夠隨意使用,由於大多數人在實驗時使用的單位都是納秒,其實差異不是很大。我找到一篇我認爲講解最詳細的一篇博客:StringTokenizer、split、substring對比
  • 問題2:在實現冒泡排序時,輸出錯誤
  • 問題2解決方法:通過了特別屢次DeBug以後終於發現,我設置的臨時節點temp的值會隨着node的值的變化而變化。因而我修改了代碼,再也不設置一個節點而是設置一個泛型T來儲存本來node的值。
  • 註釋內的是原來的錯誤代碼。

其餘(感悟、思考等)

  • 這回的實驗感受難點主要仍是集中在鏈表,其次是排序問題。問了不少同窗發現你們都是實驗1、實驗二和實驗四早早就作出來了,就是實驗三和實驗五比較難作。不過這回實驗仍是作得很開心的,由於讓我複習到了不少之前的知識,忽然就意識到了作課程總結的好處,這樣我每次回去翻博客的時候老是能很快翻到。
  • 不過在放假前一天在912花9個小時來作實驗這種體驗真的不但願再有第二回了。

參考資料

相關文章
相關標籤/搜索