大话数据结构(一)——线性表顺序存储结构的java实现

    在看《大话数据结构》的时候,里面诙谐的语言和讲解吸引了我,但是这本书是用C来实现的,但是作为一个手撸java的人就想着用java来实现一下这些数据结构,于是就有了这些大话数据结构之java实现。哈哈,感觉这样会让自己的理解加深不少。

    好了,不多说啦,今天是实现线性表顺序存储结构,首先我们来看看什么是线性表。

    每次去食堂吃饭就会看到排的一条条的长队,其实每一条队伍就是一个线性表,说的官方一点就是线性表是由零个或多个数据元素构成的有限序列。首先线性表是有序的,也就是说元素之间是有顺序的,如果有多个元素存在,那么第一个元素没有前驱,最后一个元素没有后继,其他的每个元素都存在前驱和后继。就像一个队伍中的第一个人的前面没人,最后一个人的后面没人,而处于中间的人的前后都是有人的。然后线性表是有限的,即线性表中所含的元素是有限的。

    接下来准确的官方描述一下线性表:若将线性表标记为(a[0],a[1],…,a[i-1],a[i],a[i+1],…,a[n]),则表中a[i-1]领先于a[i],a[i]领先与a[i+1],称a[i-1]是a[i]的直接前驱元素,a[i+1]是a[i]的直接后继元素。当i=1,2,3,4,…,n-1时,a[i]有且仅有一个直接后继,当i=1,2,3,…,n时,a[i]有且仅有一个直接前驱。线性表元素的个数n(n>=0)定义为线性表的长度,当n=0时,这个线性表称为空表。

    然后,我们再来看看线性表的顺序存储结构,线性表的顺序存储结构就是指用一段地址连续的存储单元依次存储线性表的数据元素。当看到这个结构时很容易就想到使用数组来作为存储,下面的图是关于顺序存储结构的插入删除图解:


    由顺序存储的结构就可以知道顺序存储结构的优点和缺点了:

    优点:

    1)无须为表示表中元素之间的逻辑而额外增加存储空间。

    2)可以快速地存取表中的任一位置的元素

    缺点:

    1)插入和删除操作需要移动大量元素,时间复杂度高。

    2)当线性表长度变化较大时,难以确定存储的容量。

    3)造成存储空间的碎片。

    插入和删除的过程看图就能很清楚的明白了,下面是关于顺序存储结构的代码实现:

    其中包含有插入,删除,根据位置查找元素,根据元素查找位置,清空线性表等操作

顺序线性表SequenceList

  1. package SeqList;  
  2.   
  3. import java.util.Arrays;  
  4.   
  5. /** 
  6.  * Created by jiangxs on 17-5-20. 
  7.  */  
  8. public class SequenceList<T> {  
  9.     private final int DEFAULT_SIZE = 16;  
  10.     private int capacity; //保存数组的长度  
  11.     private Object[] elementData;//定义一个数组,用来保存数据线性表  
  12.     private int size;//用来存放数据线性表中当前元素的个数  
  13.   
  14.     //以默认长度创建空的线性表  
  15.     public SequenceList(){  
  16.         capacity = DEFAULT_SIZE;  
  17.         elementData = new Object[capacity];  
  18.     }  
  19.   
  20.     /** 
  21.      * description:以指定长度来创建一个线性表 
  22.      * @param initSize 指定的长度 
  23.      */  
  24.     public SequenceList(int initSize){  
  25.         capacity = 1;  
  26.         while (capacity < initSize){  
  27.             //通过循环将capacity设置为大于initSize的最小值  
  28.             capacity = capacity << 1;  
  29.         }  
  30.         elementData = new Object[capacity];  
  31.         size++;  
  32.     }  
  33.   
  34.     //获取线性表的大小  
  35.     public int getSize(){  
  36.         return size;  
  37.     }  
  38.   
  39.     //获取索引i处的元素  
  40.     public T getElement(int i){  
  41.         if (i<0 || i>size-1)  
  42.             throw new IndexOutOfBoundsException(“输入索引超过了线性的范围”);  
  43.         return (T)elementData[i];  
  44.     }  
  45.   
  46.     //根据元素查找在线性表中的位置,未查找到返回-1  
  47.     public int getIndex(T element){  
  48.         for (int i = 0; i < size; i++){  
  49.             if (elementData[i].equals(element))  
  50.                 return i;  
  51.         }  
  52.         return -1;  
  53.     }  
  54.   
  55.     //保证数组容量大小  
  56.     private void ensureCapacity(int minCapacity){  
  57.         //如果原有数组长度小于目前所需数组长度  
  58.         if (minCapacity > capacity)  
  59.             //不断将capacity*2直到capacity最小且大于minCapacity  
  60.             while (capacity < minCapacity)  
  61.                 capacity <<= 1;  
  62.         elementData = Arrays.copyOf(elementData,capacity);  
  63.     }  
  64.   
  65.     /** 
  66.      * 向顺序线性表中的指定位置插入元素 
  67.      * @param element 要插入的元素 
  68.      * @param index 插入元素的位置 
  69.      */  
  70.     public void insert(T element,int index){  
  71.         if (index < 0 || index > size)  
  72.             throw new IndexOutOfBoundsException(“插入元素位置超过线性表范围”);  
  73.         ensureCapacity(size+1);  
  74.         //将索引处之后的元素向后移动  
  75.         System.arraycopy(elementData,index,elementData,index+1,size-index);  
  76.         elementData[index] = element;  
  77.         size++;  
  78.     }  
  79.   
  80.     /** 
  81.      * 删除指定位置元素 
  82.      * 返回被删除的元素 
  83.      * @param index 输入要删除的元素位置 
  84.      */  
  85.     public T delete(int index){  
  86.         if (index < 0 || index > size)  
  87.             throw new IndexOutOfBoundsException(“删除位置不在线性表索引范围内”);  
  88.         T old = (T)elementData[index];  
  89.         int numMove = size - index -1;  
  90.         if (numMove > 0)  
  91.             System.arraycopy(elementData,index+1,elementData,index,numMove);  
  92.         elementData[–size] = null;  
  93.         return old;  
  94.     }  
  95.   
  96.     //向顺序线性表中添加一个元素  
  97.     public void add(T element){  
  98.         insert(element,size);  
  99.     }  
  100.   
  101.     //向线性表中删除一个元素  
  102.     public T remove(){  
  103.         return delete(size-1);  
  104.     }  
  105.   
  106.     //检查线性表是否为空  
  107.     public boolean isEmpty(){  
  108.         return size == 0;  
  109.     }  
  110.   
  111.     //清空线性表  
  112.     public void clear(){  
  113.         //将所有元素置为空  
  114.         Arrays.fill(elementData,null);  
  115.         size = 0;  
  116.     }  
  117.   
  118.     public String toString(){  
  119.         if (isEmpty())  
  120.             return “[]”;  
  121.         else {  
  122.             StringBuilder sb = new StringBuilder(“[“);  
  123.             for (int i = 0;i<size;i++){  
  124.                 sb.append(elementData[i].toString()+” ”);  
  125.             }  
  126.             int len = sb.length();  
  127.             return sb.delete(len-1,len).append(“]”).toString();  
  128.         }  
  129.     }  
  130. }  
package SeqList;

import java.util.Arrays;

/**
 * Created by jiangxs on 17-5-20.
 */
public class SequenceList<T> {
    private final int DEFAULT_SIZE = 16;
    private int capacity; //保存数组的长度
    private Object[] elementData;//定义一个数组,用来保存数据线性表
    private int size;//用来存放数据线性表中当前元素的个数

    //以默认长度创建空的线性表
    public SequenceList(){
        capacity = DEFAULT_SIZE;
        elementData = new Object[capacity];
    }

    /**
     * description:以指定长度来创建一个线性表
     * @param initSize 指定的长度
     */
    public SequenceList(int initSize){
        capacity = 1;
        while (capacity < initSize){
            //通过循环将capacity设置为大于initSize的最小值
            capacity = capacity << 1;
        }
        elementData = new Object[capacity];
        size++;
    }

    //获取线性表的大小
    public int getSize(){
        return size;
    }

    //获取索引i处的元素
    public T getElement(int i){
        if (i<0 || i>size-1)
            throw new IndexOutOfBoundsException("输入索引超过了线性的范围");
        return (T)elementData[i];
    }

    //根据元素查找在线性表中的位置,未查找到返回-1
    public int getIndex(T element){
        for (int i = 0; i < size; i++){
            if (elementData[i].equals(element))
                return i;
        }
        return -1;
    }

    //保证数组容量大小
    private void ensureCapacity(int minCapacity){
        //如果原有数组长度小于目前所需数组长度
        if (minCapacity > capacity)
            //不断将capacity*2直到capacity最小且大于minCapacity
            while (capacity < minCapacity)
                capacity <<= 1;
        elementData = Arrays.copyOf(elementData,capacity);
    }

    /**
     * 向顺序线性表中的指定位置插入元素
     * @param element 要插入的元素
     * @param index 插入元素的位置
     */
    public void insert(T element,int index){
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("插入元素位置超过线性表范围");
        ensureCapacity(size+1);
        //将索引处之后的元素向后移动
        System.arraycopy(elementData,index,elementData,index+1,size-index);
        elementData[index] = element;
        size++;
    }

    /**
     * 删除指定位置元素
     * 返回被删除的元素
     * @param index 输入要删除的元素位置
     */
    public T delete(int index){
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("删除位置不在线性表索引范围内");
        T old = (T)elementData[index];
        int numMove = size - index -1;
        if (numMove > 0)
            System.arraycopy(elementData,index+1,elementData,index,numMove);
        elementData[--size] = null;
        return old;
    }

    //向顺序线性表中添加一个元素
    public void add(T element){
        insert(element,size);
    }

    //向线性表中删除一个元素
    public T remove(){
        return delete(size-1);
    }

    //检查线性表是否为空
    public boolean isEmpty(){
        return size == 0;
    }

    //清空线性表
    public void clear(){
        //将所有元素置为空
        Arrays.fill(elementData,null);
        size = 0;
    }

    public String toString(){
        if (isEmpty())
            return "[]";
        else {
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0;i<size;i++){
                sb.append(elementData[i].toString()+" ");
            }
            int len = sb.length();
            return sb.delete(len-1,len).append("]").toString();
        }
    }
}


测试代码:

  1. package SeqList;  
  2.   
  3. /** 
  4.  * Created by jiangxs on 17-5-20. 
  5.  */  
  6. public class SequenceListDemo {  
  7.     public static void main(String[] args) {  
  8.         SequenceList<String> slist = new SequenceList<String>();  
  9.         slist.add(”haha”);  
  10.         slist.add(”hehe”);  
  11.         slist.add(”xixi”);  
  12.         System.out.println(”添加元素后的顺序线性表为: ”+slist);  
  13.         slist.insert(”heihei”,2);  
  14.         System.out.println(”在线性表的位置2插入元素: ”+slist);  
  15.         slist.delete(2);  
  16.         System.out.println(”删除线性表中位置2的元素: ”+slist);  
  17.         slist.remove();  
  18.         System.out.println(”删除线性表中的一个元素: ”+slist);  
  19.         slist.getElement(1);  
  20.         System.out.println(”获得线性表位置1处的元素”+slist);  
  21.         System.out.println(”获取元素hehe所在位置: ”+slist.getIndex(“hehe”));  
  22.         //清空线性表  
  23.         slist.clear();  
  24.         System.out.println(”清空线性表”);  
  25.         System.out.println(”清空后线性表是否为空: ”+slist.isEmpty());  
  26.     }  
  27. }  


测试结果:

  1. 添加元素后的顺序线性表为: [haha hehe xixi]  
  2. 在线性表的位置2插入元素: [haha hehe heihei xixi]  
  3. 删除线性表中位置2的元素: [haha hehe xixi]  
  4. 删除线性表中的一个元素: [haha hehe]  
  5. 获得线性表位置1处的元素[haha hehe]  
  6. 获取元素hehe所在位置: 1  
  7. 清空线性表  
  8. 清空后线性表是否为空: true  
  9.   
  10. Process finished with exit code 0  

参考:《大话数据结构》

    在看《大话数据结构》的时候,里面诙谐的语言和讲解吸引了我,但是这本书是用C来实现的,但是作为一个手撸java的人就想着用java来实现一下这些数据结构,于是就有了这些大话数据结构之java实现。哈哈,感觉这样会让自己的理解加深不少。

    好了,不多说啦,今天是实现线性表顺序存储结构,首先我们来看看什么是线性表。

    每次去食堂吃饭就会看到排的一条条的长队,其实每一条队伍就是一个线性表,说的官方一点就是线性表是由零个或多个数据元素构成的有限序列。首先线性表是有序的,也就是说元素之间是有顺序的,如果有多个元素存在,那么第一个元素没有前驱,最后一个元素没有后继,其他的每个元素都存在前驱和后继。就像一个队伍中的第一个人的前面没人,最后一个人的后面没人,而处于中间的人的前后都是有人的。然后线性表是有限的,即线性表中所含的元素是有限的。

    接下来准确的官方描述一下线性表:若将线性表标记为(a[0],a[1],…,a[i-1],a[i],a[i+1],…,a[n]),则表中a[i-1]领先于a[i],a[i]领先与a[i+1],称a[i-1]是a[i]的直接前驱元素,a[i+1]是a[i]的直接后继元素。当i=1,2,3,4,…,n-1时,a[i]有且仅有一个直接后继,当i=1,2,3,…,n时,a[i]有且仅有一个直接前驱。线性表元素的个数n(n>=0)定义为线性表的长度,当n=0时,这个线性表称为空表。

    然后,我们再来看看线性表的顺序存储结构,线性表的顺序存储结构就是指用一段地址连续的存储单元依次存储线性表的数据元素。当看到这个结构时很容易就想到使用数组来作为存储,下面的图是关于顺序存储结构的插入删除图解:


    由顺序存储的结构就可以知道顺序存储结构的优点和缺点了:

    优点:

    1)无须为表示表中元素之间的逻辑而额外增加存储空间。

    2)可以快速地存取表中的任一位置的元素

    缺点:

    1)插入和删除操作需要移动大量元素,时间复杂度高。

    2)当线性表长度变化较大时,难以确定存储的容量。

    3)造成存储空间的碎片。

    插入和删除的过程看图就能很清楚的明白了,下面是关于顺序存储结构的代码实现:

    其中包含有插入,删除,根据位置查找元素,根据元素查找位置,清空线性表等操作

顺序线性表SequenceList

  1. package SeqList;  
  2.   
  3. import java.util.Arrays;  
  4.   
  5. /** 
  6.  * Created by jiangxs on 17-5-20. 
  7.  */  
  8. public class SequenceList<T> {  
  9.     private final int DEFAULT_SIZE = 16;  
  10.     private int capacity; //保存数组的长度  
  11.     private Object[] elementData;//定义一个数组,用来保存数据线性表  
  12.     private int size;//用来存放数据线性表中当前元素的个数  
  13.   
  14.     //以默认长度创建空的线性表  
  15.     public SequenceList(){  
  16.         capacity = DEFAULT_SIZE;  
  17.         elementData = new Object[capacity];  
  18.     }  
  19.   
  20.     /** 
  21.      * description:以指定长度来创建一个线性表 
  22.      * @param initSize 指定的长度 
  23.      */  
  24.     public SequenceList(int initSize){  
  25.         capacity = 1;  
  26.         while (capacity < initSize){  
  27.             //通过循环将capacity设置为大于initSize的最小值  
  28.             capacity = capacity << 1;  
  29.         }  
  30.         elementData = new Object[capacity];  
  31.         size++;  
  32.     }  
  33.   
  34.     //获取线性表的大小  
  35.     public int getSize(){  
  36.         return size;  
  37.     }  
  38.   
  39.     //获取索引i处的元素  
  40.     public T getElement(int i){  
  41.         if (i<0 || i>size-1)  
  42.             throw new IndexOutOfBoundsException(“输入索引超过了线性的范围”);  
  43.         return (T)elementData[i];  
  44.     }  
  45.   
  46.     //根据元素查找在线性表中的位置,未查找到返回-1  
  47.     public int getIndex(T element){  
  48.         for (int i = 0; i < size; i++){  
  49.             if (elementData[i].equals(element))  
  50.                 return i;  
  51.         }  
  52.         return -1;  
  53.     }  
  54.   
  55.     //保证数组容量大小  
  56.     private void ensureCapacity(int minCapacity){  
  57.         //如果原有数组长度小于目前所需数组长度  
  58.         if (minCapacity > capacity)  
  59.             //不断将capacity*2直到capacity最小且大于minCapacity  
  60.             while (capacity < minCapacity)  
  61.                 capacity <<= 1;  
  62.         elementData = Arrays.copyOf(elementData,capacity);  
  63.     }  
  64.   
  65.     /** 
  66.      * 向顺序线性表中的指定位置插入元素 
  67.      * @param element 要插入的元素 
  68.      * @param index 插入元素的位置 
  69.      */  
  70.     public void insert(T element,int index){  
  71.         if (index < 0 || index > size)  
  72.             throw new IndexOutOfBoundsException(“插入元素位置超过线性表范围”);  
  73.         ensureCapacity(size+1);  
  74.         //将索引处之后的元素向后移动  
  75.         System.arraycopy(elementData,index,elementData,index+1,size-index);  
  76.         elementData[index] = element;  
  77.         size++;  
  78.     }  
  79.   
  80.     /** 
  81.      * 删除指定位置元素 
  82.      * 返回被删除的元素 
  83.      * @param index 输入要删除的元素位置 
  84.      */  
  85.     public T delete(int index){  
  86.         if (index < 0 || index > size)  
  87.             throw new IndexOutOfBoundsException(“删除位置不在线性表索引范围内”);  
  88.         T old = (T)elementData[index];  
  89.         int numMove = size - index -1;  
  90.         if (numMove > 0)  
  91.             System.arraycopy(elementData,index+1,elementData,index,numMove);  
  92.         elementData[–size] = null;  
  93.         return old;  
  94.     }  
  95.   
  96.     //向顺序线性表中添加一个元素  
  97.     public void add(T element){  
  98.         insert(element,size);  
  99.     }  
  100.   
  101.     //向线性表中删除一个元素  
  102.     public T remove(){  
  103.         return delete(size-1);  
  104.     }  
  105.   
  106.     //检查线性表是否为空  
  107.     public boolean isEmpty(){  
  108.         return size == 0;  
  109.     }  
  110.   
  111.     //清空线性表  
  112.     public void clear(){  
  113.         //将所有元素置为空  
  114.         Arrays.fill(elementData,null);  
  115.         size = 0;  
  116.     }  
  117.   
  118.     public String toString(){  
  119.         if (isEmpty())  
  120.             return “[]”;  
  121.         else {  
  122.             StringBuilder sb = new StringBuilder(“[“);  
  123.             for (int i = 0;i<size;i++){  
  124.                 sb.append(elementData[i].toString()+” ”);  
  125.             }  
  126.             int len = sb.length();  
  127.             return sb.delete(len-1,len).append(“]”).toString();  
  128.         }  
  129.     }  
  130. }  
package SeqList;

import java.util.Arrays;

/**
 * Created by jiangxs on 17-5-20.
 */
public class SequenceList<T> {
    private final int DEFAULT_SIZE = 16;
    private int capacity; //保存数组的长度
    private Object[] elementData;//定义一个数组,用来保存数据线性表
    private int size;//用来存放数据线性表中当前元素的个数

    //以默认长度创建空的线性表
    public SequenceList(){
        capacity = DEFAULT_SIZE;
        elementData = new Object[capacity];
    }

    /**
     * description:以指定长度来创建一个线性表
     * @param initSize 指定的长度
     */
    public SequenceList(int initSize){
        capacity = 1;
        while (capacity < initSize){
            //通过循环将capacity设置为大于initSize的最小值
            capacity = capacity << 1;
        }
        elementData = new Object[capacity];
        size++;
    }

    //获取线性表的大小
    public int getSize(){
        return size;
    }

    //获取索引i处的元素
    public T getElement(int i){
        if (i<0 || i>size-1)
            throw new IndexOutOfBoundsException("输入索引超过了线性的范围");
        return (T)elementData[i];
    }

    //根据元素查找在线性表中的位置,未查找到返回-1
    public int getIndex(T element){
        for (int i = 0; i < size; i++){
            if (elementData[i].equals(element))
                return i;
        }
        return -1;
    }

    //保证数组容量大小
    private void ensureCapacity(int minCapacity){
        //如果原有数组长度小于目前所需数组长度
        if (minCapacity > capacity)
            //不断将capacity*2直到capacity最小且大于minCapacity
            while (capacity < minCapacity)
                capacity <<= 1;
        elementData = Arrays.copyOf(elementData,capacity);
    }

    /**
     * 向顺序线性表中的指定位置插入元素
     * @param element 要插入的元素
     * @param index 插入元素的位置
     */
    public void insert(T element,int index){
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("插入元素位置超过线性表范围");
        ensureCapacity(size+1);
        //将索引处之后的元素向后移动
        System.arraycopy(elementData,index,elementData,index+1,size-index);
        elementData[index] = element;
        size++;
    }

    /**
     * 删除指定位置元素
     * 返回被删除的元素
     * @param index 输入要删除的元素位置
     */
    public T delete(int index){
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("删除位置不在线性表索引范围内");
        T old = (T)elementData[index];
        int numMove = size - index -1;
        if (numMove > 0)
            System.arraycopy(elementData,index+1,elementData,index,numMove);
        elementData[--size] = null;
        return old;
    }

    //向顺序线性表中添加一个元素
    public void add(T element){
        insert(element,size);
    }

    //向线性表中删除一个元素
    public T remove(){
        return delete(size-1);
    }

    //检查线性表是否为空
    public boolean isEmpty(){
        return size == 0;
    }

    //清空线性表
    public void clear(){
        //将所有元素置为空
        Arrays.fill(elementData,null);
        size = 0;
    }

    public String toString(){
        if (isEmpty())
            return "[]";
        else {
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0;i<size;i++){
                sb.append(elementData[i].toString()+" ");
            }
            int len = sb.length();
            return sb.delete(len-1,len).append("]").toString();
        }
    }
}


测试代码:

  1. package SeqList;  
  2.   
  3. /** 
  4.  * Created by jiangxs on 17-5-20. 
  5.  */  
  6. public class SequenceListDemo {  
  7.     public static void main(String[] args) {  
  8.         SequenceList<String> slist = new SequenceList<String>();  
  9.         slist.add(”haha”);  
  10.         slist.add(”hehe”);  
  11.         slist.add(”xixi”);  
  12.         System.out.println(”添加元素后的顺序线性表为: ”+slist);  
  13.         slist.insert(”heihei”,2);  
  14.         System.out.println(”在线性表的位置2插入元素: ”+slist);  
  15.         slist.delete(2);  
  16.         System.out.println(”删除线性表中位置2的元素: ”+slist);  
  17.         slist.remove();  
  18.         System.out.println(”删除线性表中的一个元素: ”+slist);  
  19.         slist.getElement(1);  
  20.         System.out.println(”获得线性表位置1处的元素”+slist);  
  21.         System.out.println(”获取元素hehe所在位置: ”+slist.getIndex(“hehe”));  
  22.         //清空线性表  
  23.         slist.clear();  
  24.         System.out.println(”清空线性表”);  
  25.         System.out.println(”清空后线性表是否为空: ”+slist.isEmpty());  
  26.     }  
  27. }  


测试结果:

  1. 添加元素后的顺序线性表为: [haha hehe xixi]  
  2. 在线性表的位置2插入元素: [haha hehe heihei xixi]  
  3. 删除线性表中位置2的元素: [haha hehe xixi]  
  4. 删除线性表中的一个元素: [haha hehe]  
  5. 获得线性表位置1处的元素[haha hehe]  
  6. 获取元素hehe所在位置: 1  
  7. 清空线性表  
  8. 清空后线性表是否为空: true  
  9.   
  10. Process finished with exit code 0  

参考:《大话数据结构》

猜你喜欢

转载自blog.csdn.net/qq_33127597/article/details/79681591