大話數據結構系列之靜態鏈表(四)

定義

組成

讓數組的元素都是由兩個數據域組成,data 和 cur。
數組的每個下標都對應一個 data 和一個 cur。數據域 data,用來存放數據元素;而遊標 cur 相當於單鏈表中的 next 指針,存放該勻速的後繼在數組中的下標。

靜態鏈表的插入元素

例子:
新增元素丙,並插入到下標爲3的位置
操作步驟:
在實際數組中是在編號爲7的地方直接放置丙元素,數據域的下標置爲3
將元素 乙 的數據域下標置爲 7,那麼在進行遍歷時,它會首先找到編號爲 7 的丙元素。
然後在依據 丙 元素的數據域下標,找到了編號爲 3 的元素丁,如此完成了數據的插入

在這裏插入圖片描述

在這裏插入圖片描述

存在意義

靜態鏈表其實是爲了給沒有指針的高級語言設計的一種實現單鏈表能力的方法。

靜態鏈表的優缺點

優點
在插入和刪除操作時,只需要修改遊標,不需要移動元素,從而改進了順序存儲結構中插入和刪除操作需要移動大量元素的缺點。

缺點
沒有解決連續存儲分配帶來的表長難以確定的問題。
失去了順序存儲結構隨機存取的特性(及在查詢時的時間複雜度爲 O[n] )

代碼實現( C 、Java )

C 語言

#include "string.h"
#include "ctype.h"      

#include "stdio.h"    
#include "stdlib.h"   
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 1000 /* 存儲空間初始分配量 */

typedef int Status;           /* Status是函數的類型,其值是函數結果狀態代碼,如OK等 */
typedef char ElemType;        /* ElemType類型根據實際情況而定,這裏假設爲char */


Status visit(ElemType c)
{
    printf("%c ",c);
    return OK;
}

/* 線性表的靜態鏈表存儲結構 */
typedef struct 
{
    ElemType data;
    int cur;  /* 遊標(Cursor) ,爲0時表示無指向 */
} Component,StaticLinkList[MAXSIZE];


/* 將一維數組space中各分量鏈成一個備用鏈表,space[0].cur爲頭指針,"0"表示空指針 */
Status InitList(StaticLinkList space) 
{
    int i;
    for (i=0; i<MAXSIZE-1; i++)  
        space[i].cur = i+1;
    space[MAXSIZE-1].cur = 0; /* 目前靜態鏈表爲空,最後一個元素的cur爲0 */
    return OK;
}


/* 若備用空間鏈表非空,則返回分配的結點下標,否則返回0 */
int Malloc_SSL(StaticLinkList space) 
{ 
    int i = space[0].cur;                   /* 當前數組第一個元素的cur存的值 */
                                            /* 就是要返回的第一個備用空閒的下標 */
    if (space[0]. cur)         
        space[0]. cur = space[i].cur;       /* 由於要拿出一個分量來使用了, */
                                            /* 所以我們就得把它的下一個 */
                                            /* 分量用來做備用 */
    return i;
}


/*  將下標爲k的空閒結點回收到備用鏈表 */
void Free_SSL(StaticLinkList space, int k) 
{  
    space[k].cur = space[0].cur;    /* 把第一個元素的cur值賦給要刪除的分量cur */
    space[0].cur = k;               /* 把要刪除的分量下標賦值給第一個元素的cur */
}

/* 初始條件:靜態鏈表L已存在。操作結果:返回L中數據元素個數 */
int ListLength(StaticLinkList L)
{
    int j=0;
    int i=L[MAXSIZE-1].cur;
    while(i)
    {
        i=L[i].cur;
        j++;
    }
    return j;
}

/*  在L中第i個元素之前插入新的數據元素e   */
Status ListInsert(StaticLinkList L, int i, ElemType e)   
{  
    int j, k, l;   
    k = MAXSIZE - 1;   /* 注意k首先是最後一個元素的下標 */
    if (i < 1 || i > ListLength(L) + 1)   
        return ERROR;   
    j = Malloc_SSL(L);   /* 獲得空閒分量的下標 */
    if (j)   
    {   
        L[j].data = e;   /* 將數據賦值給此分量的data */
        for(l = 1; l <= i - 1; l++)   /* 找到第i個元素之前的位置 */
           k = L[k].cur;           
        L[j].cur = L[k].cur;    /* 把第i個元素之前的cur賦值給新元素的cur */
        L[k].cur = j;           /* 把新元素的下標賦值給第i個元素之前元素的ur */
        return OK;   
    }   
    return ERROR;   
}

/*  刪除在L中第i個數據元素   */
Status ListDelete(StaticLinkList L, int i)   
{ 
    int j, k;   
    if (i < 1 || i > ListLength(L))   
        return ERROR;   
    k = MAXSIZE - 1;   
    for (j = 1; j <= i - 1; j++)   
        k = L[k].cur;   
    j = L[k].cur;   
    L[k].cur = L[j].cur;   
    Free_SSL(L, j);   
    return OK;   
} 

Status ListTraverse(StaticLinkList L)
{
    int j=0;
    int i=L[MAXSIZE-1].cur;
    while(i)
    {
            visit(L[i].data);
            i=L[i].cur;
            j++;
    }
    return j;
    printf("\n");
    return OK;
}


int main()
{
    StaticLinkList L;
    Status i;
    i=InitList(L);
    printf("初始化L後:L.length=%d\n",ListLength(L));

    i=ListInsert(L,1,'F');
    i=ListInsert(L,1,'E');
    i=ListInsert(L,1,'D');
    i=ListInsert(L,1,'B');
    i=ListInsert(L,1,'A');

    printf("\n在L的表頭依次插入FEDBA後:\nL.data=");
    ListTraverse(L); 

    i=ListInsert(L,3,'C');
    printf("\n在L的“B”與“D”之間插入“C”後:\nL.data=");
    ListTraverse(L); 

    i=ListDelete(L,1);
    printf("\n在L的刪除“A”後:\nL.data=");
    ListTraverse(L); 

    printf("\n");

    return 0;
}

Java 語言

package com.example;

public class StaticLinkList<T> {

    //對比插入元素的結果圖片*
    
    //摘自博客:https://www.cnblogs.com/ityizhainan/p/6004964.html 
    private Element<T>[] linkList = null; 
    private int DEFAULT_SIZE = 4;//默認存儲大小
    private int currentFree = 0;//指向當前空閒位置
    private int size = 1;
    
    @SuppressWarnings("hiding")
    class Element<T>{
        int data;
        int cur;
    }
    
    /**
     * 靜態鏈表的長度
     * @return
     */
    public int length(){
        return size-1;
    }
    /**
     * 靜態鏈表的初始化
     */
    public StaticLinkList(){
        linkList = new Element[DEFAULT_SIZE];
        for (int i = 0; i < linkList.length; i++) {
            linkList[i] = new Element<T>();
            linkList[i].data = -1;
            linkList[i].cur = i+1;
        }
        //當前空閒節點從1開始,因爲第0個節點設置成了頭結點,設置爲空,不
        //存儲數據
        currentFree = 1;
    }
    
    /**
     * 給鏈表添加數據,每當鏈表滿了就給鏈表添加額外的空間
     * @param data
     */
    public void add(int data){
        if(size<linkList.length){
            linkList[currentFree].data = data;
            currentFree = linkList[currentFree].cur;
            size++;
        }else{//鏈表已滿,給鏈表添加空間
            addLinkSpace();
            linkList[currentFree].data = data;
            currentFree = linkList[currentFree].cur;
            size++;
        }
    }
    /**
     * 得到索引指定的數據
     * @param index
     * @return
     */
    public int get(int index){
        if(index>size-1&&index<0)
            throw new IndexOutOfBoundsException("數組越界,索引不合法");
        else{
            //這裏index+1也是因爲多了一個空的頭節點
            return linkList[index+1].data;
        }
    }
    /**
     * 刪除指定位置的節點
     * @param index
     */
    public void delete(int index){

        index = index+1;
        if(index<1||index>=size){
            System.out.println("超出鏈表長度");
        }else if(index == size-1){
            size--;
            linkList = (Element[]) getTrueIndex(linkList,size);
        }else{
            int i = 0;
            while(index!=linkList[i].cur){
                i++;
            }
            int j = 0;
            while(currentFree!=linkList[j].cur){
                j++;
            }
            linkList[i].cur = linkList[index].cur;
            linkList[j].cur = index;
            linkList[index].cur = currentFree;
            currentFree = index;
            size--;
            linkList = (Element[]) getTrueIndex(linkList,size);
        }
    }
    /**
     * 增加鏈表空間
     */
    public void addLinkSpace(){
        DEFAULT_SIZE+=8;
        Element<T>[] link = linkList;
        linkList = new Element[DEFAULT_SIZE];
        System.arraycopy(link, 0, linkList, 0, link.length);
        for (int i = link.length; i < DEFAULT_SIZE; i++) {
            linkList[i] = new Element<T>();
            linkList[i].data = -1;
            linkList[i].cur = i+1;
        }
        currentFree = link.length;
    }

    /**
     * 根據指定的位置插入數據
     * @param index
     * @param data
     */
    public void insert(int index,int data){
        //這裏加1的原因是因爲鏈表的第0位爲空節點,這裏設置的頭節點爲空
        index = index + 1;
        if(size<linkList.length){
            if(index>size&&index<0)
                System.out.println("數組越界,超出數組長度");
            else if(index == size){
                linkList[currentFree].data = data;
                currentFree = linkList[currentFree].cur;
                size++;
            }else{
                /******未按邏輯順序排序而插入數據的寫法,因爲未排序,則當前索引的上個節點的索引不一定是當前索引減1****/
                int i = 0;
                while(index!=linkList[i].cur){
                    i++;
                }
                int j = 0;
                while(currentFree!=linkList[j].cur){
                    j++;
                }
                linkList[i].cur = currentFree;
                linkList[j].cur = linkList[currentFree].cur;
                linkList[currentFree].data = data;
                linkList[currentFree].cur = index;
                currentFree = linkList[j].cur;
                size++;
                //每次插入後將鏈表按邏輯順序重新排序,是爲了方便輸出查看。
                linkList = (Element[]) getTrueIndex(linkList,size);
            }
        }else{
            addLinkSpace();
            insert(index, data);
        }
    }
    /**
     * 按照邏輯順序重新排列
     * @param link 
     * @return
     */
    public Object getTrueIndex(Element[] link,int size){
        Element[] linkList1 = new Element[linkList.length];
        int k =0;
        for (int i = 0; i < linkList.length; i++) {
            linkList1[i] = new Element();
            linkList1[i].data = link[k].data;
            k = link[k].cur;
            linkList1[i].cur = i+1;
        }
        //插入時,currentFree肯定是最後一個了,但刪除後,currentFree就不一定是最後一位了
        currentFree = size;
        return linkList1;
    }
    
    /**
     * @param args
     */
    public static void main(String[] args) {
         StaticLinkList listA = new StaticLinkList();
            int la[]={
                    2,3,5,8,9,6,7
            };
            for (int i = 0; i < la.length; i++) {
                listA.add(la[i]);
            }
            listA.delete(6);
            listA.delete(0);

            listA.insert(3, 88);
            listA.insert(3, 78);
            for (int i = 0; i < listA.length(); i++) {
                System.out.println(listA.get(i));
            }
    }
}
發佈了240 篇原創文章 · 獲贊 91 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章