//自定义一个链表 public class LinkList<E> { //初始状态时没有任何数据;头结点为null;尾结点为null;数据个数为0 public Node<E> head=null; public Node<E> last=null; private int num=0; //存放数据(添加结点)的方法 public void add(E e){ //根据数据创建结点对象 Node<E> node = new Node<E>(e); //如果链表中有元素;就将新结点放到last结点后面 if(last!=null){ //把node赋给last的后一个 last.next=node; //把last赋给node的前一个 node.front=last; //把node赋给last last=node; }else{//如果链表中没有元素;node就是第一个结点;node既是头结点又是尾结点 last=node; head=node; } num++; } //根据下标取出数据的方法 public E get(int index){ Node<E> node = getNode(index); return node.date; } //插入数据的方法 public void insert(int index, E e){ Node<E> node = new Node<E>(e); //找到index位置的结点 Node<E> n1 = getNode(index); //找到t1前一个结点 Node<E> n2 = n1.front; //如果插入的下标为0; if(index==0){ //插入结点node后一个结点为原来0位置的的结点 node.next=n1; //插入结点的前一个结点为null node.front=null; //把node赋值给头结点 head=node; }else{//如果插入的下标不是0 //建立node与前一个结点的关系 n2.next=node; node.front=n2; //建立node与后一个结点的关系 node.next=n1; n1.front=node; } num++; } //根据下标删除数据 public void delete(int index){ //找到要删除的结点 Node<E> n1 = getNode(index); //找到n1前一个位置 Node<E> n2=n1.front; //找到n1后一个位置 Node<E> n3=n1.next; //删除第一个结点 if(index==0){ head=head.next; n1.next=null; n1=null; num--; return;} //删除尾结点 if(n1.next==null){ n2.next=null; } else{ //删除中间结点 n2.next=n3; n3.front=n2; } num--; } //根据内容删除 public void delete(E e){ //调用根据下标删除的方法 delete(getIndex(e)); } //获得链表长度 public int size(){ return num; } //根据内容确定下标 private int getIndex(E e){ //遍历链表中的数据 for(int i=0;i<num;i++){ //把每次遍历的数据赋给e2 E e2=get(i); //如果e2的值和e相等就返回e2的下标 if(e2.equals(e)){ return i; } } //如果没找到返回-1 return -1; } //根据下标确定结点 private Node<E> getNode(int index){ int t=-1; //如果传入的下标大于等于0小于链表长度 if(index>=0&&index<num){ Node<E> n = head; //如果头结点不为null while(n!=null){ //t就自加 t++; //如果t等于传入下标时就返回 if(t==index){ break; } //如果不等于传入的下标;把n的下一个结点赋给n继续遍历 n=n.next; } return n; }else{//如果传入的下标小于0大于等于链表长度 //抛出异常 throw new IndexOutOfBoundsException("下标超出边界!index:"+index+ ",size:"+num); } } } //内部的结点类 class Node<E>{ //结点的数据 E date; // 对下一个结点的引用 Node<E> next; //对前一个结点的引用 Node<E> front; //创建结点对象时必须制定数据 public Node(E e){ date =e; } }
//测试双向链表 public class Test { public static void main(String[] args) { //创建一个双向链表对象 LinkList<String> list =new LinkList<String>(); //添加数据 list.add("AA"); list.add("BB"); list.add("CC"); for(int i=0;i<list.size();i++){ String t =list.get(i); System.out.println(t); } System.out.println("-----------------------"); //获取数据 String s = list.get(0); System.out.println(s); //插入数据 list.insert(1, "新的数据"); for(int i=0;i<list.size();i++){ String j =list.get(i); System.out.println(j); } System.out.println("---------------------------"); //根据下标删除数据 list.delete(0); //根据内容删除数据 list.delete("新的数据"); for(int i=0;i<list.size();i++){ String b =list.get(i); System.out.println(b); } System.out.println("----------------------------"); //获得链表的长度 int num=list.size(); System.out.println(num); } }
上次我写了数据结构中的长度可变数组,今天我写的是自定义一个双向链表。
1.什么是链表?
链表是一种非顺序的存储数据的数据结构,元素的逻辑顺序是通过链表中的指定链接次序实现的;
链表是由结点组成;每个结点分为两部分:数据元素和前后结点地址的指针。
2.链表和长度可变数组的优缺点?
数组优点:存储元素的地址是连续的;在读取数据时可以根据下标快速的找到数据。
数组缺点:在插入和删除数据时需要移动其他数据项;还需把原数组中的数据复制到新数组中; 在操作大量数据时这样需要大量时间。
链表优点 :存储元素的地址是不连续的;在插入和删除大量数据时不需要复制原来的数据只需在原来数据基础上插入。
链表缺点:在读取数据时需要在链表中依次的寻找直到找到为止。
3.怎样实现于操作链表?
先定义一个节点类
a.存放数据
b.取出数据
c.删除数据
d.修改数据
e.数据个数