单链表结构:物理存储结构上不连续,逻辑上连续,大小不固定。
单链表主要是以一个个节点组成,结点中又包含了两个域:1.存储数据的数据域 2.存储指针的指针域(java是以一个变量存储下一个结点的内存地址)
单链表插入操作:
s.next=p.next;
p.next=s;(注意插入的顺序)
单链表的删除操作:
....----->p(结点)------>z(结点)------>.....
如果要删除Z结点
p.next=z.next;
1.结点类
1 public class ListNode { 2 Object data; 3 ListNode next; 4 5 public ListNode(Object element) 6 { 7 this.data=element; 8 } 9 }
2.MyList接口
1 public interface MyList<T>{ 2 //新增一个元素 3 void add(T element); 4 //删除与输入元素相同的元素 5 void delete(T element); 6 //根据索引删除元素 7 void delete(int index); 8 //更新元素 9 void update(int index,T newelement); 10 //三种查询方法 11 boolean contains(T element); 12 13 T at(int index); 14 15 int indexOf(T element); 16 }
3.SingleLinkedList类
1 public class SingleLinkedList<T> implements MyList<T>{ 2 private ListNode first; 3 private ListNode last; 4 private int size=0; 5 6 @Override 7 public void add(T element) { 8 if(first==null) 9 { 10 first=new ListNode(element); 11 last=first; 12 }else { 13 last.next=new ListNode(element); 14 last=last.next; 15 } 16 size++; 17 } 18 19 @Override 20 public void delete(T element) { 21 ListNode p=first; 22 ListNode pre=null; 23 while(p!=null) 24 { 25 if(p.data.equals(element)) 26 { 27 if(p==first) 28 { 29 first=first.next;//first等于first的下一个结点 30 } 31 else 32 { 33 pre.next=p.next;//相等结点的前驱结点的指针指向该结点的后驱结点 34 } 35 size--; 36 break; 37 } 38 pre=p; 39 p=p.next; 40 } 41 } 42 43 @Override 44 public void delete(int index) { 45 int i=0;//计数 46 ListNode p=first; 47 ListNode pre=null; 48 while(p!=null) 49 { 50 if(i==index) 51 { 52 if(p==first) 53 first=first.next; 54 else 55 pre.next=p.next; 56 size--; 57 break; 58 } 59 pre=p; 60 p=p.next; 61 i++; 62 } 63 64 } 65 66 @Override 67 public void update(int index, T newelement) { 68 if(index>=size&&index<0) 69 return ; 70 int i=0;//计数 71 ListNode p=first; 72 while(p!=null) 73 { 74 if(index==i) 75 { 76 p.data=newelement; 77 break; 78 } 79 p=p.next; 80 i++; 81 } 82 83 } 84 85 @Override 86 public boolean contains(T element) { 87 ListNode p=first; 88 while(p!=null) 89 { 90 if(p.data.equals(element)) 91 return true; 92 p=p.next; 93 } 94 return false; 95 } 96 97 @Override 98 public T at(int index) { 99 if(index>=size&&index<0) 100 return null; 101 int i=0;//计数 102 ListNode p=first; 103 while(p!=null) 104 { 105 if(index==i) 106 { 107 return (T) p.data; 108 } 109 p=p.next; 110 i++; 111 } 112 return null; 113 } 114 115 @Override 116 public int indexOf(T element) { 117 int i=0; 118 ListNode p=first; 119 while(p!=null) 120 { 121 if(p.data.equals(element)) 122 { 123 return i; 124 } 125 p=p.next; 126 i++; 127 } 128 return -1; 129 } 130 131 @Override 132 public String toString() 133 { 134 StringBuilder sb=new StringBuilder("["); 135 ListNode p=first; 136 while(p!=null) 137 { 138 sb.append(p.data); 139 if(p.next!=null) 140 sb.append(","); 141 p=p.next; 142 } 143 sb.append("]"); 144 return sb.toString(); 145 } 146 147 public int getSize() 148 { 149 return size; 150 } 151 152 }
顺序表和单链表的比较:
顺序表:
优点:主要优点是支持随机读取,以及内存空间利用效率高;
缺点:主要缺点是需要预先给出数组的最大数据元素个数,而这通常很难准确作到。当实际的数据元素个数超过了预先给出的个数,会发生异常。另外,顺序表插入和删除操作时需要移动较多的数据元素。
单链表:
优点:主要优点是不需要预先给出数据元素的最大个数。另外,单链表插入和删除操作时不需要移动数据元素;
缺点:主要缺点是每个结点中要有一个指针,因此单链表的空间利用率略低于顺序表的。另外,单链表不支持随机读取,单链表取数据元素操作的时间复杂度为O(n);而顺序表支持随机读取,顺序表取数据元素操作的时间复杂度为O(1)。