Java資料結構和演算法(一)連結串列

sodawyx發表於2020-10-16

資料結構和演算法(一)連結串列

前言

資料結構和演算法是程式的基礎,是程式設計師基本功的展現。即使是在現在主流框架不斷成熟的今天,我們也不應輕視。畢竟做個只會調API的程式設計師也無法提升自己的核心競爭實力。除此之外,要想深入瞭解主流框架,我們也要關注其原始碼的實現。而在鞏固資料結構和演算法的基礎上來看主流框架的原始碼也許會有更深的認識。
本人本科專業為通訊方向,研究生轉為電腦科學與技術方向。《資料結構和演算法》課程在本科也沒有系統的學習,在輔修課程有一定涉獵,但說實話學的不是很認真。因此,在這裡也希望用一些空閒時間(研0)做一些總結。此外,基於Java的資料結構並不是學習的主流,但我未來使用的主力語言應該就是Java了,在這裡也統一使用Java語言描述。

連結串列

Java中對於List的使用有詳細的介紹,在這裡我們就不一一講述順序表的使用了。我們直接引入連結串列。

單連結串列

單連結串列的儲存結構

/**
 * 單連結串列的資料結構
 * @param <T>
 */
public class LinkedNode<T> {
    private T data; //泛型資料T
    private LinkedNode<T> next; //指向下一個節點本身的指標
    //新建一個節點即都為空
    public LinkedNode() {
        data = null;
        next = null;
    }
    //新建一個帶資料的節點
    public LinkedNode(T element){
        data = element;
        next = null;
    }

    public T getData() {
        return data;
    }

    public void setData(T element) {
        data = element;
    }

    public LinkedNode<T> getNext(){
        return next;
    }

    public void setNext(LinkedNode<T> successor) {
        next = successor;
    }
}

單連結串列的操作及實現

對於一個單連結串列,我們可以建立LinkedList.java類來表示,其中其例項變數為頭節點first

private LinkedNode<T> first;

其相關操作如下

初始化一個空連結串列
//初始化一個空連結串列
    public LinkedList() {
        first = new LinkedNode<T>();
    }
判斷列表是否為空
//判斷連結串列是否為空
    public boolean isEmpty() {
        if(first.getNext() == null) return true;
        else return false;
    }

遍歷連結串列
//遍歷連結串列
    public void itrList() {
        LinkedNode<T> p = first.getNext();
        while(p != null) {
            System.out.println(p.getData());
            p = p.getNext();
        }
    }
求單連結串列的長度
//求單連結串列的長度
    public int getlen() {
        int length = 0;
        LinkedNode<T> p = first.getNext();
        while (p != null) {
            p = p.getNext();
            length++;
        }
        return length;
    }
按值查詢
//按值查詢
    public int findByValue(T element) {
        LinkedNode<T> p = first.getNext();
        int count = 1;
        while (p != null){
            if (p.getData() == element) return count;
            p = p.getNext();
            count++;
        }
        return 0;   //若沒找到則返回0
    }
按位查詢
//按位查詢
    public T findByIndex(int i) throws Exception {
        LinkedNode<T> p = first.getNext();
        int count = 1;
        while (p != null && count < i) {
            p = p.getNext();
            count++;
        }
        if (p == null) throw new Exception("位置異常"); //沒找到則丟擲異常
        return p.getData();
    }
插入操作
//插入操作
    public void insert(int i, T element) throws Exception {
        LinkedNode<T> p = first; //這裡從頭節點開始,因為有可能從頭節點後第一個開始新增
        int count = 1;
        while (p != null && count < i) {
            p = p.getNext();
            count ++;
        }
        if (p == null) throw new Exception("位置異常"); //沒找到則丟擲異常
        LinkedNode<T> node = new LinkedNode<>(element); //將資料封裝為新節點,注意目前next指的是null
        node.setNext(p.getNext()); //將node的下一位指向原有p節點的下一位
        p.setNext(node); //將p節點的下一位指向node
    }
刪除操作
//刪除操作
    public void delete(int i) throws Exception {
        LinkedNode<T> p = first.getNext();
        int count = 1;
        while (p != null && count < i-1) {
            p = p.getNext();
            count++;
        }
        if (p == null || p.getNext() == null) throw new Exception("位置異常"); //沒找到則丟擲異常
        LinkedNode<T> q = p.getNext();
        p.setNext(q.getNext());
    }
頭插法將陣列轉化為連結串列
//頭插法將陣列轉化為連結串列
    public void headInsert(T[] init) {
        first = new LinkedNode<T>();
        for (int i = 0; i < init.length; i++) {
            LinkedNode<T> node = new LinkedNode<>(init[i]);
            node.setNext(first.getNext());
            first.setNext(node);
        }
    }
尾插法將陣列轉化為連結串列
//尾插法將陣列轉化為連結串列
    public void rearInsert(T[] init) {
        first = new LinkedNode<>();
        LinkedNode<T> rear = first;
        for (int i = 0; i < init.length; i++) {
            LinkedNode<T> node = new LinkedNode<T>(init[i]);
            rear.setNext(node.getNext());
            rear = node;
        }
    }

雙連結串列

雙連結串列在單連結串列的基礎上增加了頭指標,其大多數操作可參照單連結串列進行,在這裡就不一一贅述了。在這裡強調一下插入操作和刪除操作。

插入操作

應十分注意其操作順序

node.setPrior(p);
node.setNext(p.getNext());
(p.getNext()).setPrior(node);
p.setNext(node);
刪除操作
(p.getPrior()).setNext(p.getNext);
(p.getNext()).setPrior(p.getPrior());

迴圈連結串列

尾節點不再指向null,指向first頭節點。
因此在判斷結束的時候,可以通過p.getNext() != first來進行判斷。

相關文章