线性表的Java实现
一、概念
对于常用的数据结构,可分为线性结构和非线性结构,线性结构主要是线性表,非线性结构主要是数和图。当n>0时,表可表示为:(a0,a1,a2,a3,…an)
1、 线性表的特征:
1、存在唯一的被称作”第一个”的数据元素
2、存在唯一的一个称作”最后一个的”数据元素”
3、除第一个之外,集合中的每个数据元素均只有一个前驱
4、除最后一个之外,集合中每个元素均只有一个后继
2、线性表的基本操作
1、初始化:
2、返回线性表长度
3、获取指定索引处元素
4、按值查找元素位置
5、直接插入数据元素
6、向指定位置插入元素
7、直接删除元素
8、删除指定位置元素
二、顺序存储结构
线性表的顺序结构是指用一组地址连续的存储单元依次存放线性表的元素。下面采用数组实现顺序结构线性表。
1 import java.util.Arrays; 2 public class Sequence<T> { 3 privateObject[] elementData;//定义一个数组 4 privateint DEFAULT_SIZE = 1; //数组默认大小 5 privateint capacity; //数组容量 6 privateint size = 0; //当前数组大小 7 //初始化 8 public Sequence(){ 9 capacity= this.DEFAULT_SIZE; 10 elementData= new Object[capacity]; 11 } 12 13 public Sequence()(T element){ 14 this(); 15 elementData[0]= element; 16 size++; 17 } 18 19 //返回线性表长度 20 public int length(){ 21 return this.size; 22 } 23 24 //返回指定索引处元素。 25 public T getElementByIndex(int index){ 26 27 if(index< 0 || index > (size-1)){ 28 System.out.println("索引范围越界!!!"); 29 System.exit(0); 30 } 31 return (T)elementData[index]; 32 } 33 //按值查找数据元素的位置 34 public int getIndexByValue(T value){ 35 for(int i = 0; i < elementData.length;i++ ){ 36 if(value.equals(elementData[i])){ 37 return i; 38 } 39 } 40 return -1;//未找到则返回-1 41 } 42 43 //向指定位置插入元素 44 public void insert(T element,int index){ 45 ensureCapacity(); //确保线性表容量够 46 if(index>= 0 && index < size){ 47 int i = 0; 48 //将插入位置之后元素挨个后移1 49 for(i= (size-1); i >= index;i--){ 50 elementData[i+1]= elementData[i]; 51 } 52 elementData[i+1]= element;//插入该元素 53 size++; //数组当前容量+1 54 } 55 else{ 56 throw new IndexOutOfBoundsException("插入元素位置越界!!!"); 57 } 58 } 59 60 //想线性表末尾添加元素 61 public void add(T element){ 62 ensureCapacity(); //确保线性表容量够 63 elementData[size]= element; 64 size++; 65 } 66 67 //删除线性表中指定位置元素 68 public void delete(int index){ 69 if(index>= 0 && index < size){ 70 int i; 71 //将要删除元素位置之后的元素挨个前移1,通过覆盖删除 72 for(i= index+1;i < size;i++){ 73 elementData[i-1]= elementData[i]; 74 } 75 elementData[size-1]= null; 76 } 77 else{ 78 thrownew IndexOutOfBoundsException("所要删除元素位置越界!!!"); 79 } 80 } 81 82 //删除指定元素 83 public void delete(T value){ 84 int index = this.getIndexByValue(value); 85 if(index!= -1){ 86 this.delete(index); 87 } 88 else{ 89 System.out.println("您要删除的元素并不存在"); 90 System.exit(0); 91 } 92 size--; 93 } 94 95 //判断线性表是否为空 96 public boolean isEmpty(){ 97 boolean b = false; 98 if(this.length()!= 0){ 99 b= true; 100 } 101 return b; 102 } 103 104 //清空线性表 105 public void clear(){ 106 for(Object o:elementData){ 107 o= null; 108 } 109 size= 0; 110 } 111 112 //显示线性表中所有元素 113 public void view(){ 114 System.out.print("当前线性表中元素为:"); 115 for(int i = 0;i < size;i++){ 116 System.out.print(elementData[i]+ " "); 117 } 118 System.out.print("\n"); 119 } 120 121 //扩充线性表容量 122 public void ensureCapacity(){ 123 while((size+1)> capacity){ 124 capacity=capacity * 2; //线性表容量每次增大一倍 125 elementData= Arrays.copyOf(elementData, capacity); 126 } 127 } 128 129 public static void main(String[] args) { 130 Sequence<String> sequence = new Sequence<>(); 131 sequence.add("hello"); 132 sequence.add("world"); 133 sequence.add("java"); 134 sequence.add("perfect"); 135 sequence.view(); 136 sequence.insert("haha",1); 137 sequence.view(); 138 System.out.println("索引为3的元素为:" +sequence.getElementByIndex(3)); 139 System.out.println("字符串perfect的索引号为:"+ sequence.getIndexByValue("perfect")); 140 sequence.delete("hello"); 141 sequence.view(); 142 sequence.clear(); 143 System.out.println("clear之后线性表长度为:"+ sequence.length()); 144 } 145 } 146
三、链式存储结构
1、概念
链式存储结构的线性表(简称为链表)采用一组任意的存储单元存放线性表中的数据元素。链式存储结构的线性表不是按线性的逻辑顺序来保存数据元素,它需要在每个数据元素里保存一个引用下一个数据元素的引用。
节点 = 数据元素 + 引用下一个节点的引用 + 引用上一个节点的引用
2、单链表基本操作
建立单链表方法:1头插法建表 2尾插法建表
查找操作:1按index查找指定数据元素 2在链表中查找指定的数据元素的index
插入操作:在第index个索引处插入元素
删除操作:删除第index个节点
3、单链表具体实现
1 public class LinkList<T>{ 2 //定义Node节点 3 private class Node{ 4 private T data; 5 private Node next; 6 7 public Node(){ 8 9 } 10 public Node(T element,Node next){ 11 this.data= element; 12 this.next= next; 13 } 14 } 15 //成员变量 16 private Node header;//头节点 17 private Node tail; //尾节点 18 private int size = 0; //链表长度 19 20 public LinkList(){ 21 header= null; 22 tail= header; 23 } 24 25 public LinkList(T element){ 26 header= new Node(element,null); 27 tail= header; 28 } 29 30 //获取链表中指定索引处的元素 31 public T get(int index){ 32 return this.getNodeByIndex(index).data; 33 } 34 35 36 //获取链表中指定索引处Node 37 public Node getNodeByIndex(int index){ 38 this.checkBorder(index); 39 Node currentNode = header; 40 for(int i = 0;i < size && currentNode !=null;i++,currentNode =currentNode.next){ 41 if(i== index){ 42 return currentNode; 43 } 44 } 45 return null; 46 } 47 48 //向指定索引处插入元素 49 public void insert(T element,int index){ 50 this.checkBorder(index); 51 if(index== 0){ 52 this.addAtHeader(element); 53 } 54 else{ 55 NodeprevNode =this.getNodeByIndex(index-1);//获取插入位置的前向Node 56 prevNode.next=new Node(element,prevNode.next); 57 } 58 size++; 59 } 60 61 //删除指定索引处Node 62 public T delete(int index){ 63 this.checkBorder(index); 64 Nodedel = null; 65 //删除的是header 66 if(index== 0){ 67 del= header; 68 header= header.next; 69 } 70 else{ 71 NodeprevNode =this.getNodeByIndex(index); 72 del= prevNode.next; 73 prevNode.next= del.next; //将prevNode的后向Node设置为del.next 74 del.next= null; 75 } 76 size--; 77 returndel.data; 78 } 79 80 //头插法向链表中添加元素 81 public void addAtHeader(T element){ 82 header= new Node(element,header);//将新添加的Node的next设置为原先的header,然后将新的Node设置为新的header 83 if(tail==null){ 84 tail= header; 85 } 86 size++; 87 } 88 89 //尾插法 90 public void add(T element){ 91 //链表为空的情况 92 if(header==null){ 93 header= new Node(element,null); 94 tail= header; 95 } 96 else{ 97 tail.next= new Node(element, null); //将tail节点的next设置为new Node 98 tail= tail.next;//将new Node设置为tail 99 } 100 size++; 101 } 102 //遍历整个链表 103 public void view(){ 104 NodecurrentNode = header; 105 System.out.print("当前链表元素:"); 106 while(currentNode!=null){ 107 System.out.print(currentNode.data+ " "); 108 currentNode= currentNode.next; 109 } 110 System.out.println(""); 111 112 } 113 114 //检测索引是否越界 115 private void checkBorder(int index){ 116 if(index< 0 || index > size-1){ 117 thrownew IndexOutOfBoundsException("链表索引已越界"); 118 } 119 } 120 121 public int length(){ 122 return this.size; 123 } 124 125 public static void main(String args[]){ 126 LinkList<String> linkList =new LinkList<>(); 127 linkList.add("hello"); 128 linkList.add("world"); 129 linkList.addAtHeader("header"); 130 System.out.println("当前链表长度为:"+ linkList.length()); 131 linkList.view(); 132 System.out.print("插入test之后,"); 133 linkList.insert("test",2); 134 linkList.view(); 135 linkList.delete(2); 136 System.out.print("删除索引2处元素后,"); 137 linkList.view(); 138 System.out.println("索引1处元素为:" +linkList.get(1)); 139 } 140 }
4、双链表实现
1 public class DoubleLinkList<T> { 2 3 //定义双向链表节点 4 private class Node{ 5 private T data; 6 private Node prev; 7 private Node next; 8 public Node(){ 9 10 } 11 public Node(T element,Node prev,Node next){ 12 this.data= element; 13 this.prev= prev; 14 this.next= next; 15 } 16 } 17 18 private Node header; 19 private Node tail; 20 private int size = 0; 21 22 public DoubleLinkList(){ 23 header= null; 24 tail= null; 25 } 26 27 public DoubleLinkList(T element){ 28 header= new Node(element,null,null); 29 tail= header; 30 size++; 31 } 32 //获取链表长度 33 public int length(){ 34 return this.size; 35 } 36 37 //检测index是否越界 38 public void checkBorder(int index){ 39 if(index< 0 || index > size-1){ 40 throw new IndexOutOfBoundsException("链表索引已越界"); 41 } 42 } 43 44 //获取指定索引处Node 45 public Node getNodeByIndex(int index){ 46 checkBorder(index);//越界检测 47 if(index< size/2){ 48 NodecurrentNode = header; 49 for(int i = 0;i < size/2;i++,currentNode = currentNode.next ){ 50 if(i== index){ 51 return currentNode; 52 } 53 } 54 } 55 else{ 56 NodecurrentNode = tail; 57 for(int i = size-1;i >= size/2;i--,currentNode = currentNode.prev){ 58 if(i== index){ 59 returncurrentNode; 60 } 61 } 62 } 63 return null; 64 } 65 66 //获取链表中指定索引处的元素值 67 public T get(int index){ 68 return this.getNodeByIndex(index).data; 69 } 70 71 //根据元素值查找元素索引 72 public int locate(T element){ 73 Node currentNode = this.header; 74 for(int i = 0;i < size-1;i++,currentNode = currentNode.next){ 75 if(currentNode.data.equals(element)){ 76 returni; 77 } 78 } 79 return -1; 80 81 } 82 83 //向链表中以尾插法添加元素 84 public void add(T element){ 85 if(size== 0){ 86 header= new Node(element,null,null); 87 tail= header; 88 } 89 else{ 90 Node newNode =new Node(element,tail,null); 91 tail.next= newNode; 92 tail= newNode; 93 } 94 size++; 95 } 96 97 //头插法向链表添加元素 98 public void addAtHeader(T element){ 99 if(size== 0){ 100 header= new Node(element,null,null); 101 tail= header; 102 } 103 else{ 104 Node newNode =new Node(element,null,header); 105 header.prev= newNode; 106 header= newNode; 107 } 108 size++; 109 } 110 111 112 //根据索引插入元素 113 public void insert(T element,int index){ 114 this.checkBorder(index); 115 Node prevNode = this.getNodeByIndex(index-1); 116 Node nextNode = this.getNodeByIndex(index); 117 Node insertNode = new Node(element, prevNode, nextNode); 118 nextNode.prev= insertNode; 119 prevNode.next= insertNode; 120 size++; 121 } 122 123 //根据索引删除元素 124 public void delete(int index){ 125 this.checkBorder(index); 126 Node prevDelNode = this.getNodeByIndex(index-1); 127 Node nextDelNode = this.getNodeByIndex(index+1); 128 prevDelNode.next= nextDelNode; 129 nextDelNode.prev= prevDelNode; 130 size--; 131 } 132 133 //遍历链表中元素 134 public void view(){ 135 System.out.print("当前链表中元素为:"); 136 for(int i = 0;i < size;i++){ 137 System.out.print(this.get(i)+ " "); 138 } 139 System.out.println(); 140 } 141 142 public static void main(String[] args) { 143 DoubleLinkList<String> doubleLinkList =new DoubleLinkList<>(); 144 doubleLinkList.add("hello"); 145 doubleLinkList.add("world"); 146 doubleLinkList.insert("test",1); 147 doubleLinkList.addAtHeader("first"); 148 doubleLinkList.view(); 149 System.out.println("索引为0处的元素值为:"+ doubleLinkList.get(0)); 150 System.out.println("test字符串在链表中索引号为:" + doubleLinkList.locate("test")); 151 doubleLinkList.delete(1); 152 System.out.print("删除索引号为1元素后,"); 153 doubleLinkList.view(); 154 } 155 156 }
注:本文部分内容参考自《疯狂Java程序员的基本修养》和《数据结构(C语言版)》