數據結構Java實現----線性表與順序表

一、線性結構

如果一個數據元素序列滿足:

(1)除第一個和最後一個數據元素外,每個數據元素只有一個前驅數據元素和一個後繼數據元素;

(2)第一個數據元素沒有前驅數據元素;

(3)最後一個數據元素沒有後繼數據元素。

則稱這樣的數據結構爲線性結構。

 

二、線性表抽象數據類型:

1、線性表抽象數據類型的概念:

線性表抽象數據類型主要包括兩個方面:既數據集合和該數據集合上的操作集合。

數據集合:

  可以表示爲a0,a1,a2,...an-1,每個數據元素的數據類型可以是任意的類型。

操作集合包括如下:

1.求元素個數

2.插入

3.刪除

4.查找

5.判斷是否爲空

2、設計線性表抽象數據類型的Java接口:

代碼如下:

//線性表接口
public interface List {
    //獲得線性表長度
    public int size();
    //判斷線性表是否爲空
    public boolean isEmpty();
    //插入元素
    public void insert(int index,Object obj) throws Exception;
    //刪除元素
    public void delete(int index) throws Exception;
    //獲取指定位置的元素
    public Object get(int index) throws Exception;
}

然後我們讓子類去實現這個接口就行了。

 

三、順序表:(在物理存儲結構上連續,大小固定)

1、順序表的概念:

計算機有兩種基本的存儲結構(物理存儲結構):順序結構、離散結構。使用順序結構實現的線性表稱爲順序表。如下圖所示:

d3384f05-39d1-46d9-a580-bf4b531d740c

Java內存中,棧內存和堆內存佔了很大一部分空間:棧內存的存儲是順序結構,堆內存的存儲是離散結構。

 

2、設計順序表類:

我們在上面第二段的List接口基礎之上,設計一個順序表:

(1)List.java:(線性表,和上面的第二段中代碼一樣)

//線性表接口
public interface List {
    //獲得線性表長度
    public int size();
    //判斷線性表是否爲空
    public boolean isEmpty();
    //插入元素
    public void insert(int index, Object obj) throws Exception;
    //刪除元素
    public void delete(int index) throws Exception;
    //獲取指定位置的元素
    public Object get(int index) throws Exception;
}

 

(2)SequenceList.java:(核心代碼)

 1 public class SequenceList implements List {
 2 
 3     //默認的順序表的最大長度
 4     final int defaultSize = 10;
 5     //最大長度
 6     int maxSize;
 7     //當前長度
 8     int size;
 9     //對象數組
10     Object[] listArray;
11 
12 
13     public SequenceList() {
14         init(defaultSize);
15     }
16 
17     public SequenceList(int size) {
18         init(size);
19     }
20 
21     //順序表的初始化方法
22     private void init(int size) {
23         maxSize = size;
24         this.size = 0;
25         listArray = new Object[size];
26     }
27 
28     @Override
29     public void delete(int index) throws Exception {
30         // TODO Auto-generated method stub
31         if (isEmpty()) {
32             throw new Exception("順序表爲空,無法刪除!");
33         }
34         if (index < 0 || index > size - 1) {
35             throw new Exception("參數錯誤!");
36         }
37         //移動元素
38         for (int j = index; j < size - 1; j++) {
39             listArray[j] = listArray[j + 1];
40         }
41         size--;
42     }
43 
44     @Override
45     public Object get(int index) throws Exception {
46         // TODO Auto-generated method stub
47         if (index < 0 || index >= size) {
48             throw new Exception("參數錯誤!");
49         }
50         return listArray[index];
51     }
52 
53     @Override
54     public void insert(int index, Object obj) throws Exception {
55         // TODO Auto-generated method stub
56         //如果當前線性表已滿,那就不允許插入數據
57         if (size == maxSize) {
58             throw new Exception("順序表已滿,無法插入!");
59         }
60         //插入位置編號是否合法
61         if (index < 0 || index > size) {
62             throw new Exception("參數錯誤!");
63         }
64         //移動元素
65         for (int j = size - 1; j >= index; j--) {
66             listArray[j + 1] = listArray[j];
67         }
68 
69         listArray[index] = obj;  //不管當前線性表的size是否爲零,這句話都能正常執行,即都能正常插入
70         size++;
71 
72     }
73 
74     @Override
75     public boolean isEmpty() {
76         // TODO Auto-generated method stub
77         return size == 0;
78     }
79 
80     @Override
81     public int size() {
82         // TODO Auto-generated method stub
83         return size;
84     }
85 }

 

我們來看一下第54行的插入操作insert()方法:如果需要在index位置插入一個數據,那麼index後面的元素就要整體往後移動一位。這裏面需要特別注意的是:

插入操作:移動元素時,要從後往前操作,不能從前往後操作,不然元素會被覆蓋的

刪除元素:移動元素時,要從前往後操作。

(3)測試類:

public class Test {

    public static void main(String[] args) {

        SequenceList list = new SequenceList(20);

        try {
            list.insert(0, 100);
            list.insert(0, 50);
            list.insert(1, 20);

            for (int i = 0; i < list.size; i++) {
                System.out.println("第" + i + "個數爲" + list.get(i));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

我們要注意插入的規則是什麼,不然會覺得這個順序表打印輸出的順序很奇怪。

運行效果:

0e1ffa91-ced8-4e2a-b247-9d19b51b2c19

  

3、順序表效率分析:

  • 順序表插入和刪除一個元素的時間複雜度爲O(n)。
  • 順序表支持隨機訪問,順序表讀取一個元素的時間複雜度爲O(1)。因爲我們是可以通過下標直接訪問的,所以時間複雜度是固定的,和問題規模無關。

4、順序表的優缺點:

  • 順序表的優點是:支持隨機訪問;空間利用率高(連續分配,不存在空間浪費)。
  • 順序表的缺點是:大小固定(一開始就要固定順序表的最大長度)插入和刪除元素需要移動大量的數據。

 

5、順序表的應用:

設計一個順序表,可以保存100個學生的資料,保存以下三個學生的資料,並打印輸出。

0393f396-1a75-4b69-927f-3e923f86d207

代碼實現:

(1)List.java:

  和上面的代碼保持不變

(2)SequenceList.java:

  和上面的代碼保持不變

(3)Students.java:學生類

 

//學生類
public class Students {

    private String id;// 學號
    private String name;// 姓名
    private String gender;// 性別
    private int age;// 年齡

    public Students() {

    }

    public Students(String sid, String name, String gender, int age) {
        this.id = sid;
        this.name = name;
        this.gender = gender;
        this.age = age;
    }


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "學號:" + this.getId() + " 姓名:" + this.getName() + " 性別:" + this.getGender() + " 年齡:" + this.getAge();
    }

}

(4)Test.java:

 1 public class Test {
 2 
 3     /**
 4      * @param args
 5      */
 6     public static void main(String[] args) {
 7         // TODO Auto-generated method stub
 8         SequenceList list = new SequenceList(100);
 9 
10         try {
11             list.insert(list.size, new Students("S0001", "張三", "男", 18)); //第一個參數list.size代表的是:我每次都是在順序表的最後一個位置(當前線性表的長度的位置)進行插入操作。這一行裏,size是等於0
12             list.insert(list.size, new Students("S0002", "李四", "男", 19));
13             list.insert(list.size, new Students("S0003", "王五", "女", 21));
14 
15             for (int i = 0; i < list.size; i++) {
16                 System.out.println(list.get(i));
17             }
18 
19         } catch (Exception ex) {
20             ex.printStackTrace();
21         }
22     }
23 
24 }

 

注意第11行的註釋:第一個參數list.size代表的是:我每次都是在順序表的最後一個位置(當前線性表的長度的位置)進行插入操作;這樣的話,遍歷時纔是按照張三、李四、王五的順序進行輸出的。

運行效果:

b0ccde4d-daf2-42c6-91e3-4f2f7a4e4b61

歡迎工作一到五年的Java工程師朋友們加入Java技術交流羣:659270626
羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章