大话数据结构系列之静态链表(四)

牧云@^-^@ 提交于 2020-01-23 08:10:07

定义

组成

让数组的元素都是由两个数据域组成,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));
            }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!