Java实现线性表的顺序和链式存储

什么是线性表?

​ 线性表(Linear List),是由同类型数据元素构成有序序列的线性结构,表中元素个数称为线性表的长度;线性表没有元素时,称为空表;表的起始位置称为表头,表的结束位置称为表尾

抽象数据类型描述

​ 类型名称:线性表(List)

​ 数据对象集:线性表是n(n>=0)个元素构成的有序序列(a,a2,...,an)

​ 操作集:Item 表示元素类型,整数 i 表示位置

  • boolean isEmpty() 线性表是否为空
  • int size() 线性表中的元素个数
  • void insert(Item item, int i) 在 i 位置插入元素
  • void delete(int i) 在第i个位置删除数据(即删除数组下标为i-1这个位置)
  • int find(Item item) 查找某个元素,如果找到,返回下标;否则返回-1

顺序存储实现(固定大小)

​ 创建一个泛型类List:

public class List<Item>{
    private Item[] data; // 泛型数组存储数据
    private int last = -1; // last表示最后一个元素的下标
}

​ 构造函数:

public List(int size){
        data = (Item[]) new Object[size]; // java不允许创建泛型数组,所以需要用到类型转换
}

插入数据

​ 在这里,我们插入数据的位置范围是1n+1,即第一个位置到最后一个位置+1(这里的n就表示当前List中的元素个数)。所以我们就会发现我们在插入数据后,这些数据都是连续的。比如:在创建了List之后,数组中没有元素,元素个数为0,那么此时插入的范围就是10+1,只有1这个位置可以插入,之后再插入第二个元素,这时元素的个数已经变成了1,此时的范围是1~1+1,以此类推,存储在这个线性表中的数据总会是连续的。

image

​ 当我们向线性表中插入数据时,首先要看看这个线性表满了没有,如果满了不能插入,判断满的条件就是:last==data.length-1如果最后一个元素的下标等于数组的最后一个下标,说明满了。

​ 然后,要判断插入的位置是否合法:i < 1 || i > last+2(n+1 >= i >= 1)。

​ 之前说过,List中存储的数据是连续的,所以我们插入时不能直接插入,需要将元素往后挪出一个空位才能够在特定的位置进行插入:

// 挪动的顺序毫无疑问是从最后一个元素挪,否则你从第i个元素挪的话就会覆盖掉后面的元素
for (int j=last; j>=i-1; j--){
    data[j+1] = data[j];
}
// 插入数据
data[i-1] = item;
// last加1
last = last + 1;

删除元素

​ 和插入元素类似,只是挪动元素是往前挪动元素,填补删除后留下的空位。直接上代码:

// 如果List空,不能删除
if (isEmpty()){
    System.out.println("List为空,不能删除");
}
// 规定的删除位置在1~n+1
if (i < 1 || i > last+2){
    System.out.println("删除位置非法,无法插入!");
}
// 在删除之后需要先将数据往前挪
for (int j=i-1; j<last; j++){
    data[j] = data[j+1];
}
last = last - 1;

完整代码:

public class List<Item> {
    // Java不允许创建泛型数组,所以做强制类型转换
    private Item[] data;
    private int last = -1; // 表示List中最后一个元素的下标

    // 构造函数-创建List时指定大小
    public List(int size){
        data = (Item[]) new Object[size];
    }

    // List是否为空
    public boolean isEmpty(){
        return last==-1;
    }

    // 返回List的大小
    public int size(){
        return last+1;
    }

    // 在第i个位置插入数据(即插入到数组下标为i-1这个位置)
    public void insert(Item item, int i){
        // 如果List满了,不能插入
        if (last==data.length-1){
            System.out.println("数组满,无法插入!");
        }
        // 规定的插入位置在1~n+1之间
        if (i < 1 || i > last+2){
            System.out.println("插入位置非法,无法插入!");
        }
        // 在插入之前需要先将数据往后挪
        for (int j=last; j>=i-1; j--){
            data[j+1] = data[j];
        }
        data[i-1] = item;
        last = last + 1;
    }

    // 在第i个位置删除数据(即删除数组下标为i-1这个位置)
    public void delete(int i){
        // 如果List空,不能删除
        if (isEmpty()){
            System.out.println("List为空,不能删除");
        }
        // 规定的删除位置在1~n+1
        if (i < 1 || i > last+2){
            System.out.println("删除位置非法,无法插入!");
        }
        // 在删除之后需要先将数据往前挪
        for (int j=i-1; j<last; j++){
            data[j] = data[j+1];
        }
        last = last - 1;
    }

    // 查找某个元素,如果查找到,返回下标,否则返回-1
    public int find(Item item){
        for (int i=0; i<last+1; i++){
            if (data[i]==item){
                return i;
            }
        }
        return -1;
    }

    public void printData(){
        for (Item item:data){
            System.out.print(" " + item);
        }
        System.out.println("");
    }

    // 测试
    public static void main(String[] args) {
        List<Integer> testList = new List(5);
        testList.insert(1,1);
        testList.insert(2,2);
        testList.insert(3,3);
        testList.insert(4,4);
        testList.insert(5,5);
        testList.printData();
        testList.delete(1);
        testList.printData();
        System.out.println(testList.find(3));
    }
}

链式存储实现

​ 创建一个泛型类 LinkedList:

public class LinkedList<Item> {
    private Node head; // 线性表的表头(链表的入口)
    private int N; // 结点的数量(线性表中的元素数量)

    // node结点类
    private class Node{
        Item item;
        Node next;
        // 构造器
        public Node(Item item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
}

​ 求线性表的长度和是否为空:

public int length(){
    return N;
}

public boolean isEmpty(){
    return head==null; // 当head为null或N为0
}

​ 查找相应的位置的结点:

public Node findXth(int X){
    Node temp = head;
    int i = 1;
    // 当当前结点不为空且位置小于X时
    while (temp != null && i < X){
        temp = temp.next;
        i = i+1;
    }
    // 跳出循环有两种可能,当前结点为空或i==X
    if (i == X){
        return temp;
    } else{
        return null;
    }
}

插入数据

​ 因为是链式存储,所以不必关心空间的问题,只需care插入问题。

​ 要向链表中插入结点,首先要分插入的位置。如果是插到链表的头,需要做特殊处理:让插入结点的next的值变为head,head的值置为新插入的结点;如果插入到其他位置,只需要先找到插入位置的前一个结点p,然后是两步(顺序不能更改):1、设置插入的结点的next的值为p的next。2、改变p的next的值为插入的结点。

public void insert(int i, Item item){
    Node temp, p;
    if (i == 1){
        temp = new Node(item, head);
        head = temp;
        N = N+1;
        return;
    }
    p = findXth(i-1);
    if (p == null){
        System.out.println("参数i错误!");
        return;
    } else{
        temp = new Node(item, p.next);
        p.next = temp;
        N = N+1;
        return;
    }
}

删除数据

​ 和插入类似,区分删除的是头结点还是其他位置,删除头结点:只需head置为head的next;删除其他结点:找到前一个结点p,使其next置为p.next.next即可,java会自动进行垃圾回收。

public void delete(int i){
    Node p;
    if (i == 1){
        if (head == null){
            System.out.println("链表为空!");
            return;
        } else{
            head = head.next;
            N = N-1;
            return;
        }
    }
    p = findXth(i-1);
    if (p == null || p.next == null){
        System.out.println("第i个结点不存在!");
    } else {
        p.next = p.next.next;
        N = N-1;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容