Java数据结构——静态链表实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013293125/article/details/52947005

Java数据结构——静态链表实现

一、定义
用数组描述的链表,即称为静态链表。
在C语言中,静态链表的表现形式即为结构体数组,结构体变量包括数据域data和游标CUR。(这里的定义来自于百度百科)

二、优点
(1)这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时不需移动元素,仅需修改指针,故仍具有链式存储结构的主要优点。
(2)假如有如上的静态链表S中存储这线性表(a,b,c,d,f,g,h,i),Maxsize=11,如图所示,要在第四个元素后插入元素e,方法是:先在当前表尾加入一个元素e,即:S[9].data = e;然后修改第四个元素的游标域,将e插入到链表中,即:S[9].cursor = S[4].cursor; S[4].cursor = 9;,接着,若要删除第7个元素h,则先顺着游标链通过计数找到第7个元素存储位置6,删除的具体做法是令S[6].cursor = S[7].cursor。

三、原理图

例如一组数据如下:

(ZHAO,QIAN,SUN,LI,ZHOU,WU,ZHENG,WANG)

这里写图片描述

/**
     * 静态链表的长度
     * @return
     */
    public int length(){
        return size-1;
    }

因为有个空表头,所以长度为size-1;

/**
     * 静态链表的初始化
     */
    public StaticLinkList(){
        linkList = new Element[DEFAULT_SIZE];
        for (int i = 0; i < linkList.length; i++) {
            linkList[i] = new Element();
            linkList[i].data = -1;
            linkList[i].cur = i+1;
        }
        //当前空闲节点从1开始,因为第0个节点设置成了头结点,设置为空,不
        //存储数据
        currentFree = 1;
    }

这里是不指定链表大小的链表初始化,默认长度为DEFAULT_SIZE,第8行为链表数据初始化,第9行初始化游标cur。

/**
     * 给链表添加数据,每当链表满了就给链表添加额外的空间
     * @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++;
        }
    }

这个函数是给静态链表添加数据,第6行判断链表是否已满,currentFree是指向当前空闲位置,第7行是将要添加的数据添加到空闲位置上,第8行currentFree指向下一个空闲位置,第9行链表实际长度加1,第11行,如果链表已满,则给链表添加空间(addLinkSpace())。

/**
     * 得到索引指定的数据
     * @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;
        }
    }

第11行index+1是因为链表的第一位为空,不取到第一位。

/**
     * 删除指定位置的节点
     * @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);
        }
    }

第7行也是因为链表头结点为空。第10行是指,如果删除链表的最后一位,则执行下面的操作。第12行是将链表按照逻辑顺序重新排列,是为了显示。第14-17行是为了找到指向index的游标,如果没有12行,则指向index的游标不一定是index-1,因为物理位置连续的,逻辑位置不一定连续。18-21行是为了找到指向当前空闲位置的游标,理由同上。22行是将原指向index的游标指向原index的游标指向的位置,23行是将原指向当前空闲位置的游标指向index,表明index为空闲,24行是将index的游标指向原当前空闲位置,25行是将当前空闲位置指向index。

/**
     * 增加链表空间
     */
    public void addLinkSpace(){
        DEFAULT_SIZE+=8;
        Element[] 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();
            linkList[i].data = -1;
            linkList[i].cur = i+1;
        }
        currentFree = link.length;
    }

当链表空间不足时,增加当前链表空间。第8行是将link链表从第0个位置开始将数据复制到链表linkList里,且起始位置是从0开始,长度为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);
        }
    }

以上与delete类似,就不再介绍了。

四、完整代码示例
4.1 StaticLinkList.java

package com.yds.list;
/**
 * 因为静态链表实质上是一维数组的存储方式,所以它在物理位置上的存储
 * 是顺序的,但它是用游标来指向下一个数据的,所以根据它的下标来获取数据
 * 和按照游标的指向来获取数据是不同的,这里设置该链表的头结点为空
 * @author Administrator
 *
 */
public class StaticLinkList {

    private Element[] linkList = null; 
//  private Element[] linkList1 = null;
    private int DEFAULT_SIZE = 4;//默认存储大小
    private int currentFree = 0;//指向当前空闲位置
    private int size = 1;
    class Element{
        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();
            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[] 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();
            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;
    }
}

4.2 JavaMain.java

package com.yds.list;

public class JavaMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        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));
        }
    }

}

五、结果截图
这里写图片描述

这里还有一些关于静态链表的一些函数没有写上去,静态链表花了我一整天的时间,太绕了,所以就不继续写下去了。

猜你喜欢

转载自blog.csdn.net/u013293125/article/details/52947005