线性表

一、线性表简介

  元素与元素之间具有一对一的对应关系。
 

  • 概念:
      线性表是数学应用在计算机科学中的一种简单与基本的数据结构,是n个相同类型的元素的有限序列(n>=0)。它的关系可以看成是一种有序对的集合,目的在于表示线性表中任意两个相邻元素之间的关系。其中ai-1称为ai先行元素,ai是ai-1后继元素,可以表示为:(a1,a2,a3,an-1,……,an)。
     
  • 线性表有以下特点:

  1、有序表可以是空集合。
  2、存在唯一的第一个元素a1与唯一的最后一个元素an
  3、除第一个元素外,每一个元素都有唯一的先行者。
  4、除最后一个元素外,每一个元素都有唯一的后继者。
 

  • 线性表的基本运算:

  1、置空表initlist(L),构造一个空的线性表;
  2、求表长listLength(L),返回线性表的长度;
  3、取元素getNode(L,i),1<=i<=n;
  4、按值查找 LocateNode(L,x),返回第一个为X的结点的位置,若表中不存在则返回0
  5、插入insert(L,i,x) 在L的i位置插入x,
  6、删除delete(L,i) 删除表中的第i个元素

  • 线性表的存储结构

  静态数据结构:也称为“密集表”,它使用连续分配的内存空间来存储数据,在建立初期,必须事先声明最大可能要占用的固定内存空间。
  优点:设计简单,易读取。如:数组
  缺点:删除或加入数据困难。因为需要移动大量的数据。
 
  动态数据结构:又称为“链表”,使用不连续的内存空间存储数据,内存在程序执行时才进行分配,不需要事先声明。
  优点:能充分节省空间。
  缺点:设计麻烦;读取麻烦。

  • 顺序表与链表的对比
    在这里插入图片描述

二、线性表的实现

  • 顺序表
    在这里插入图片描述
    实现思路:
    1、 顺序表因为采用顺序存储形式,所以内部用数组来存储数据。
    2、因为存储的具体对象类型不一定,所以采用泛型操作
     
    数组操作的优缺点:
    优点:
      通过指针快速定位到表中,查询快速
    缺点:
      1.数组声明时即需要确定数组大小。当操作中超过容量时,则需要重新声明数组,并且复制当前所有数据。
      2.当需要在中间进行插入或者删除时,则需要移动大量元素(size-index个)。

定义接口:

package com.zm.linear.list;

/*现性表(列表)的接口定义*/
public interface MyList {
     //新增一个元素
    void add(Object element);
    //删除相同的元素
    void delete(Object element);
   //根据索引删除元素
    void delete(int index);

    /**将指定索引位置的元素替换成新的元素
     * @param index
     * @param newElement
     * */

    //清空数组
    void deleteAll();
    void update(int index,Object newElement);
    /***
     * @param target
     * @return
     */
    boolean contains(Object target);

    /**
     * 返回指定索引处的元素
     * @param index
     * @return
     */
    Object at(int index);
    /**
     * 查找指定元素的索引
     * @param element
     * @return
     */
    int indexOf(Object element);
}

具体实现:

package com.zm.linear.list;

public class MyArrayList implements MyList {

    //真正存储元素的底层结构
    private Object[] elements;
    //元素个数
    private int size = 0;
    //容量
    private int capacity = 10;

    public MyArrayList() {
        //创建一个数组对象
        elements = new Object[capacity];
    }

    public MyArrayList(int capacity) {
        this.capacity = capacity;
        elements = new Object[capacity];
    }

    @Override
    public void add(Object element) {
        //扩容
        if (size == capacity) {
            capacity *= 2;//增加一倍的容量
            //新建一个数组
            Object[] newArr = new Object[capacity];
            for (int i = 0; i < size; i++) {
                newArr[i] = elements[i];
            }
            //用新建的数组替换原来的数组
            elements = newArr;
        }
        //向数组中添加值
        elements[size++] = element;
    }

    //删除指定元素
    @Override
    public void delete(Object element) {
        int index=indexOf(element);
        if(index >= 0) {
            delete(index);
            delete(element);
        }
    }

    //删除指定位置的元素
    @Override
    public void delete(int index) {
       if(!(index<0||index>elements.length)){//如果指定的位置在数组之中
           //--size,说明数组中的元素个数减了1
          Object[] newArr = new Object[--size];
          //此处size的值已经变为了2
           for(int i=0;i<size;i++){
               if(i<index){
                   newArr[i]=elements[i];
               }else{
                   newArr[i]=elements[i+1];
               }
           }
           elements=newArr;
       }
    }

    @Override
    public void deleteAll() {
            for(int i = 0;i<size;i++){
                elements[i]=null;
            }
    }

    @Override
    public void update(int index, Object newElement) {
        elements[index] = newElement;
    }

    @Override
    public boolean contains(Object target) {
        return indexOf(target)>0;
    }

    @Override
    public Object at(int index) {

        return elements[index];
    }

    @Override
    public int indexOf(Object element) {
        for(int i=0;i<size;i++){
            if(elements[i].equals(element)){
                return i;
            }
        }
        return -1;
    }
    
    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("[");
        for (int i = 0; i < size; i++) {
            sb.append(elements[i] + (i == size-1 ? "" : ","));
        }
        sb.append("]");
        return sb.toString();
    }
}

测试:

package com.zm.linear.list;

import org.junit.Before;
import org.junit.Test;

public class MyListTest {

	 MyArrayList m = new MyArrayList();
    //向容器中添加元素
    @Test
    @Before
    public void addTest(){
       m.add("addas");
       m.add("tebu");
       m.add("balabala");
       m.add("addas");
       m.add("tebu");
       System.out.println(m);
    }

    //删除指定元素
    @Test
    public void delElementTest(){
        m.delete("balabala");
        System.out.println(m);
    }

    //修改数组中的元素
    @Test
    public void updateTest(){
        m.update(2,"aaaaaaaa");
        System.out.println(m);
    }

    //清空数组
    @Test
    public void deleteAllTest(){
        m.deleteAll();
        System.out.println(m);
    }
}

二、 链表

(一)单链表

在这里插入图片描述
在这里插入图片描述
定义节点:

package com.zm.linear.list;

//链表节点
public class ListNode {
     Object data;//数据
     ListNode next;//后继
     
    public ListNode() {
    }

    public ListNode(Object data) {
        this.data = data;
    }
}
package com.zm.linear.list;

public class SingleLinked implements MyList{
    /*定义链表头节点,链表必须有头节点*/
    private ListNode head;
    /*定义尾节点*/
    private ListNode last;
    //记录链表中元素的个数
    private int size;

    @Override
    public void add(Object element) {
       if(head==null){//如果头节点为空,则创建一个头节点
           head = new ListNode(element);
           last = head;
       }else{//如果头节点不为空,则添加一个节点
           //要使next可见,可以修改next的可见性或set/get方法
           last.next = new ListNode(element);
           last = last.next;
       }
       size++;
    }

    @Override
    public void delete(Object element) {
        //头指针本身不能动
        ListNode p = head;
        //记录上一次比对的节点
        ListNode pre=null;
        while(p!=null){
            if(p.data.equals(element)){
                if(p==head){//如果要删除第一个元素,需要移动头指针
                    head=head.next;
                }else{
                    pre.next=p.next;
                    break;
                }
                size--;
            }
            pre=p;
            p=p.next;

        }
    }

    @Override
    public void delete(int index) {
        if(index<0||index>=size){
            return;
        }


        int i=0;//指针指向的节点的索引
        ListNode p=head;
        ListNode pre=null;
        while (p!=null){
            if(i==index){//此时p就指向要删除的那个节点
                if(p==head){
                    head=head.next;
                }else{
                   pre.next=p.next;
                }
            }
            pre=p;
            p=p.next;
            i++;
        }
        size--;
    }

    @Override
    public void deleteAll() {

    }

    @Override
    public void update(int index, Object newElement) {
        int i=0;//指针指向的节点的索引
        ListNode p= head;
        while(p!=null){
            if(i==index){//如果现在指针指向的索引与需要修改的索引相同
                p.data=newElement;
            }
            p = p.next;//移动指针
            i++;
        }
    }

    //判断是否包含该元素
    @Override
    public boolean contains(Object target) {
        ListNode p=head;
        while (p!=null){
            if(p.data.equals(target)){
                return true;
            }
            p=p.next;//移动指针
        }
        return false;
    }

    //给定一个索引,返回节点内容
    @Override
    public Object at(int index) {
        if(index<=0||index>=size){
            return null;
        }

        int i=0;//指针指向的节点的索引
        ListNode p = head;
        while (p!=null){
            if(i==index){
                return p.data;
            }
            p=p.next;
            i++;
        }
        return null;
    }

    @Override
    public int indexOf(Object element) {
        int i=0;//记录指针指向的节点的索引
        ListNode p=head;
        while(p!=null){
            if(p.data.equals(element)){
                return i;
            }
            p=p.next;
            i++;
        }
        //如果没有找到,返回-1
        return -1;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer("[");
        ListNode p = head;
        while (p!=null){
            sb.append(p.data);
            if(p.next!=null){
                sb.append(",");
            }
            p=p.next;//移动p的指针
        }
        sb.append("]");
        return sb.toString();
    }
}

测试方法:

package com.zm.linear.list;

import org.junit.Before;
import org.junit.Test;

public class MyListTest {
	MyArrayList m = new MyArrayList();
    //向容器中添加元素
    @Test
    @Before
    public void addTest(){
       m.add("addas");
       m.add("tebu");
       m.add("balabala");
       System.out.println(m);
    }

    //删除指定元素
    @Test
    public void delElementTest(){
        m.delete("balabala");
        System.out.println(m);
    }

    //修改数组中的元素
    @Test
    public void updateTest(){
        m.update(2,"aaaaaaaa");
        System.out.println(m);
    }

    //清空数组
    @Test
    public void deleteAllTest(){
        m.deleteAll();
        System.out.println(m);
    }
}
(二)双向链表
package com.zm.linear.list;

//链表节点
public class ListNode {
    Object data;//数据
    ListNode next;//后继
    ListNode pre;//前驱
    public ListNode() {
    }

    public ListNode(Object data) {
        this.data = data;
    }
}
package com.zm.linear.list;

public class DoubleLinkList implements  MyList{
    private ListNode head = new ListNode(null);//头节点
    private ListNode last = new ListNode(null);//尾节点(亚元)
    private int size;//记录链表中元素的个数

    public DoubleLinkList() {
        //头节点没有前驱,尾节点没有后继
        head.next=last;
        last.pre=head;
    }

    @Override
    public void add(Object element) {
        ListNode newNode = new ListNode(element);
        last.pre.next=newNode;
        newNode.next = last;
        newNode.pre=last.pre;
        last.pre=newNode;
        size++;//添加一个节点
    }

    @Override
    public void delete(Object element) {
        //定义初始指针
        ListNode p = head.next;
        //初始化p的前驱
        ListNode pre = null;
        while(p != last){
            if(p.data.equals(element)){
                //前驱的后继指向现在的后继
                p.pre.next=p.next;
                p.next.pre=p.pre;
                size--;
                break;//找到了之后就跳出循环
            }
            pre = p;
            p = p.next;
        }
    }

    @Override
    public void delete(int index) {
        //判断所给的索引是否超出范围
        if(index<0||index>=size){
            return;//结束
        }
        int i=0;//记录索引值
        ListNode p = head.next;
        while(p != last){
            if(i==index){
                p.pre.next = p.next;
                p.next.pre = p.pre;
                size--;
                break;
            }
            p = p.next;
            i++;
        }
    }

    @Override
    public void deleteAll() {

    }

    @Override
    public void update(int index, Object newElement) {
        if(index<0||index>=size){
            return;
        }
        int i = 0;
        ListNode p = head.next;
        while(p!=last){
            if(i==index){
                p.data = newElement;
                break;
            }
            p = p.next;
            i++;
        }
    }

    @Override
    public boolean contains(Object target) {
        ListNode p = head.next;
        while (p!=last){
            if(p.data.equals(target)){
                return true;
            }
            p = p.next;
        }
        return false;
    }

    @Override
    public Object at(int index) {
        if(index < 0 || index >= size){
            return null;
        }
        ListNode p = head.next;
        int i = 0;//记录索引
        while(p!=last){
            if(i==index){
                return p.data;
            }
            p = p.next;
            i++;
        }

        return null;
    }

    //通过传进来的元素找索引
    @Override
    public int indexOf(Object element) {
        ListNode p = head.next;
        int i = 0;//记录索引
        while(p!=last){
            if(p.data.equals(element)){
                return i;
            }
            p = p.next;
            i++;
        }
        return -1;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer("[");
        ListNode p = head.next;
        while(p!=last){//当p还没有指向最后一个节点
            sb.append(p.data);
            if(p.next!=last){
                sb.append(",");
            }
            //移动p的指针
            p=p.next;
        }
        sb.append("]");
        return sb.toString();
    }
}
package com.zm.linear.list;

import org.junit.Before;
import org.junit.Test;

public class SingleLinkedTest {
    SingleLinked list = new SingleLinked();

    //向容器中添加元素
    @Test
    @Before
    public void addTest(){
     list.add("a");
     list.add("b");
     list.add("c");
     list.add("d");
     list.add("e");
     list.add("f");
     list.add("g");
     list.add("h");
     System.out.println(list);
    }

    //删除指定元素
    @Test
    public void delElementTest(){
        list.delete("c");
        System.out.println(list);

    }

    //删除指定索引位置上的元素
    @Test
    public void deleteIndex(){
        list.delete(0);
        System.out.println(list);
    }
    //修改数组中的元素
    @Test
    public void updateTest(){
        list.update(2,"aaaa");
        System.out.println(list);
    }

    //清空数组
    @Test
    public void deleteAllTest(){

    }

    @Test
    public void atTest(){
        Object at = list.at(2);
        System.out.println(at);
    }

    @Test
    public void containsTest(){
        boolean b = list.contains("a");
        System.out.println(b);
    }

    @Test
    public void indexOfTest(){
        int index = list.indexOf("d");
        System.out.println(index);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值