package 链表; /* * 链表是一种常见的数据结构,不同于数组有固定的长度,它是动态进行存储分配的一种结构。 * 例如一个班级有50人,但是另外一个班级只有40人,如果用数组存储它们需要定义一个长度 * 为50的数组,而其他班级并没有这么多人,这将会浪费许多的存储空间。 * 每个链表都有一个头指针,指向第一个节点。通常每个节点分为两个部分,用户存放的数据 * 和指向下一个节点的地址。每个节点依次向下指向,最后一个指向一个NULL表示链表结束。 * 在操作链表时,头指针一般不动(方便遍历所有链表数据),通常重新定义一个新的指针与 * 头指针指向相同地址,来进行数据操作。 * C语言创建链表主要代码: * struct student * { * int data; * struct student *next; * } * void main() * { * struct student *head; * struct student *p1,*p2; * int n=0; * p1=p2=(struct student*)malloc(sizeof(struct student)); * scanf("%d",&p1->data); * head=NULL; * while(p1->data!=0) * { * n++; * if(n==1) * { * head=p1; * }else{ * p2->next=p1; * } * p2 = p1; * p1=(struct student*)malloc(sizeof(struct student)); * scanf("%d",&p1->data); * } * p2->next=NULL; * } * 从上述C语言创建链表可见流程较为繁琐,数据分布在内存任意位置,通过指针指向下一个地 * 址来关联,所以在查找数据时链表没有数组直观且效率高,但是链表在进行增加、删除、插入时效 * 率比数组要好,因为链表只需要改变指针指向就可以达到增加、删除、插入效果,而数组则需要重 * 新给它们的位置排序效率低。 * 下面代码使用Java语言编写的链表,不同于C语言,Java没有指针概念,而是通过节点的引 * 用与下一个节点产生联系。创建了一个双向链表,可以向下遍历,同时可以向上遍历,且实现了链 * 表的增、删、改、查操作。(上课时老师编写的代码并没有完全实现双向链表增、删、改、查等功 * 能,我已经将代码完善。) */ public class MyLinkList<E> { private Node <E> head = null;//头节点 private Node <E> last = null;//尾节点 private int num = 0;//节点个数 public MyLinkList(){} public void add(E e){//增加链表节点 Node<E> node = new Node<E>(e);//创建一个新的节点 if(last != null)//如果尾节点last不等于空,则向后添加新的节点。 { last.next = node; node.front = last; last = node;//尾节点last向后移动 last.next = null;//且尾节点last下一个等于空,表示链表结束 } else {//如果尾节点last等于空,说明这是第一个节点,需要把新节点node定义为头、尾节点 head = node; head.front = null;//头节点head上一个为空 last = node; } num++;//节点个数加1 } public void intsert(int index,E e)//在链表第index个位置插入节点 { Node<E> node = new Node<E>(e); Node<E> n1 = getMode(index);//通过getMode方法返回第index个节点 if(index == 0){//index等于0是头节点 node.next = n1; node.front = null; head = node; n1.front = node; }else if(index == num-1){//index等于num-1是尾节点 Node<E> n2 = n1.front; n2.next = node; node.front = n2; node.next = n1; n1.front = node; last = n1; last.next = null; }else{ Node<E> n2 = n1.front; n2.next = node; node.front = n2; node.next = n1; n1.front = node; } num++; } public void delete(int index){//删除第index个节点 if(index >= 0 && index <num){ if(index==0){ head=head.next; head.front = null; }else if(index==num-1){ last = last.front; last.next =null; }else{ Node<E> n1 = getMode(index); Node<E> n2 = n1.front; n2.next=n1.next; n2 = n1.next.front; } num--; }else{ throw new IndexOutOfBoundsException("下标超出范围:index"+index+",size"+num); } } public void delete(E e){//删除链表中的某个数据的节点 int index = First(e);//获得第一个节点的位置 delete(index); } public void update(int index,E e){//更新第index个的数据 Node<E> node = getMode(index); node.data = e; } public int First(E e)//查找第一个符合要求的位置 { Node<E> node = head; int index=-1; while (node != null) { index++; if(node.data.equals(e)){ break; } node=node.next; } return index; } public int Last(E e)//查找最后一个符合要求的位置 { Node<E> node = last; int index=num; while (node != null) { index--; if(node.data.equals(e)){ break; } node=node.front; } return index; } public E get(int index){//正向获取第index个节点的数据 Node<E> node = getMode(index); return node.data; } public E getlast(int index){//反向获取第index个节点的数据 Node<E> node = getlastMode(index); return node.data; } private Node<E> getMode(int index){//正向获取第index个节点的数据的具体方法 int t = -1; if(index >= 0 && index <num){ Node<E> n = head; while(n != null) { t++; if(t == index){ break; } n=n.next; } return n; }else { throw new IndexOutOfBoundsException("下标超出范围:index"+index+",size"+num); } } private Node<E> getlastMode(int index){//反向获取第index个节点的数据的具体方法 int t = num; if(index >= 0 && index <num){ Node<E> n = last; while(n != null) { t--; if(t == index){ break; } n=n.front; } return n; }else { throw new IndexOutOfBoundsException("下标超出范围:index"+index+",size"+num); } } public void HeadInquire()//从头开始遍历链表 { Node<E> node = new Node<E>(); node = head; while(node != null){ System.out.println(node.data); node = node.next; } } public void LastInquire()//从尾开始遍历链表 { Node<E> node = new Node<E>(); node = last; while(node != null){ System.out.println(node.data); node = node.front; } } public int size(){//获取节点个数 return num; } } class Node<E>{ E data; Node<E> next;// 对下一个节点的引用 Node<E> front;// 对前一个节点的引用 public Node(){ } public Node(E e){ this.data = e; } }
package 链表; public class Main { public static void main(String[] args) { // TODO Auto-generated constructor stub MyLinkList<String> node = new MyLinkList<String>(); for(Character i=65;i<70;i++){ node.add(i.toString());//增加链表节点 } // node.intsert(0, "HH");//插入几点 // node.delete(4);//根据节点位置删除节点 // node.delete("A");//根据内容删除符合要求的第一个节点 // node.update(1, "E");//通过节点位置更新内容 // System.out.println(node.First("E"));//查找第一个符合要求的位置 // System.out.println(node.Last("E"));//查找最后一个符合要求的位置 // for(int i=0;i<node.size();i++){//通过链表节点个数正向遍历链表 // String s=node.get(i); // System.out.println(s); // } // for(int i=node.size()-1;i>=0;i--){//通过链表节点个数反向遍历链表 // String s=node.getlast(i); // System.out.println(s); // } node.HeadInquire();//通过链表是否为空正向遍历链表 // node.LastInquire();//通过链表是否为空正向遍历链表 } }