本文主要是基于Java来实现不带头节点的双向链表的一些操作
首先要创建一个类Node来描述链表的节点
其中data为链表节点的值,prev和next分别是当前节点的前一个节点和后一个节点
private class Node { private Object data; private Node prev; private Node next; private Node(Object data,Node prev,Node next) { this.data=data; this.prev=prev; this.next=next; } }
1.在链表中插入元素,下面是采用尾插法来实现
要想给链表的尾部插入一个元素,首先先要创建一个新的节点newNode,若链表为空,就是将链表的头节点和尾节点都指向新创建的节点,若链表不为空,则要要让链表的最后一个节点的下一个节点指向newNode,然后让newNode的前
一个节点指向原先的最后一个节点,具体如图所示
@Override //尾插法 public void add(Object obj) { // TODO Auto-generated method stub Node newNode=new Node(obj,null,null); if(this.first==null) { this.first=this.last=newNode; } else { Node temp=this.last; temp.next=newNode; newNode.prev=temp; this.last=newNode; } this.size++; }
首先要判断下标是否合法(下标必须要在0和链表长度之间),
(1)要删除的元素下标为第一个元素,且又是最后一个元素,则直接让链表的头节点和尾节点都指向空,若要删除的元素只是第一个元素,就将要删除的元素设为toDelete,然后将toDelete的下一个节点设为新的头节点,再让新的头节点与尾节点保持之前的状态就可以了
(2)要删除的元素为最后一个元素,方法同要删除的元素为第一个元素
(3)要删除的元素为中间的元素,则先将头节点设为要删除的元素toDelete,然后让toDelete一直往后移,toDelete点每后移一步,下标值就要减一,直至下标值等于0结束循环,然后将要删除点的相邻两个前后的点的指向从新设定,就可以了
详细如图所示
//根据下标删除元素 @Override public boolean remove(int index) { // TODO Auto-generated method stub if(index < 0 || index > this.size-1) { //下标超出范围 return false; } else if(index == 0)//要删除的为第一个元素 { if(index == this.size-1)//链表只有一个元素 { this.first = this.last = null; this.size--; return true; } Node toDelete=this.first; this.first=toDelete.next; this.first.prev=this.last; this.last.next=this.first; toDelete.next=null; toDelete.prev=null; this.size--; return true; } //删除的为最后一个元素 else if(index == this.size-1) { Node toDelete=this.last; Node newLast=toDelete.prev; this.last=newLast; newLast.next=this.first; this.first.prev=newLast; toDelete.next=null; toDelete.prev=null; this.size--; return true; } //删除的为中间的节点 else if(index > 0 && index <this.size-1) { Node toDelete=this.first; //找到下标index对应的点 while(index!=0) { toDelete=toDelete.next; index--; } Node prev=toDelete.prev; Node next=toDelete.next; prev.next=next; next.prev=prev; this.size--; return true; } return false; }
3.查看元素是否在链表中
首先先将让节点cur指向链表的第一个元素,然后将cur节点依次后移,若节点的值等于要查找的元素,则就返回true表示找到了,否则就是没找到,详细见程序
//查看元素是否存在于链表中 @Override public boolean contains(Object obj) { // TODO Auto-generated method stub if(this.first == null) { //空链表 return false; } Node cur=this.first; for(;cur!=null;cur=cur.next) { if(cur.data == obj) { return true; } } return false; }
4.找指定元素的下标
首先先将让节点cur指向链表的第一个元素,此时将下标置为0,然后创建循环,若节点cur的元素为要查找的元素,就返回该节点cur的下标indeks的值,若节点cur的元素不是要查找的元素,就让cur节点向后移,并且让下标indeks也依次加1,详细见程序
//找指定元素的下标 @Override public int indexOf(Object obj) { // TODO Auto-generated method stub if(this.first == null) { //空链表 return 0; } Node cur = this.first; int index = 0; while(cur!=null) { if(cur.data == obj) { return index; } cur=cur.next; index++; } return 0; }
5.在指定位置插入元素
首先先要判断要插入的位置是否合法,若不合法,则直接返回false,若合法,就
将让节点cur指向链表的第一个元素,然后创建循环,让节点cur依次后移,同时将下标index减一,直到下标index等于0退出循环,此时,让系节点cur的值等于要插入的元素,详细见程序
//在指定位置,插入元素 @Override public boolean set(int index, Object obj) { // TODO Auto-generated method stub if(index<0 || index>this.size-1) { return false; } Node cur=this.first; while(index!=0) { cur=cur.next; index--; } cur.data=obj; return true; }
6.根据下标找元素
首先先要判断要插入的位置是否合法,若不合法,则直接返回null,若合法,那就先判断,要寻找的下标是在链表的前半部分还是在后半部分,
(1)若是在链表的前半部分,就从链表的开头开始寻找,让节点cur开始指向链表的第一个元素,然后依次后移,同时将下标依次递减,直到下标等于0时,退出循环,此时返回节点cur的值
(2)若是在链表的后半部分,就从链表的结尾开始寻找,让节点cur开始指向链表的最后一个元素,然后依次前移,同时将下标依次递减,直到下标等于0时,退出循环,此时返回节点cur的值
//根据下标找元素 @Override public Object get(int index) { // TODO Auto-generated method stub if(index < 0 || index >this.size-1) { //非法位置 return null; } if(index<this.size/2) { Node cur=this.first; while(index!=0) { cur=cur.next; index--; } return cur.data; } else { Node cur=this.last; int loop=this.size-index-1; while(loop!=0) { cur=cur.prev; loop--; } return cur.data; } }
7.求链表的长度
若链表不为空,就直接返回链表的长度即可
//求链表长度 @Override public int length() { // TODO Auto-generated method stub if(this.first == null) { //空链表 return 0; } return this.size; }
8.销毁链表
让节点cur指向链表的第一个元素,让cur节点的下一个节点,前一个节点,cur节点的数值都为null,让将cur节点指向它的下一个节点让循环这些操作,直到cur节点为null,然后将整个链表的头节点和尾节点还有链表的长度这些都置为空null,就完成链表的销毁,详细见程序
//销毁链表 @Override public void clear() { // TODO Auto-generated method stub Node cur = this.first; while(cur!=null) { cur.next=null; cur.prev=null; cur.data=0; cur=cur.next; } this.first=null; this.last=null; this.size=0; }
9.将链表转化为数组
首先先将让节点cur指向链表的第一个元素,然后创建一个数组arry准备存放链表中的每个元素,然后将节点cur后移,让每个cur节点对应的data值都赋值到数组中,详细见程序
//将链表转化为数组 @Override public Object[] toArray() { // TODO Auto-generated method stub if(this.first == null) { //空链表 return null; } Node cur=this.first; Object[] arry=new Object[this.size]; int i=0; for(;cur!=null;cur=cur.next) { arry[i]=cur.data; i++; } return arry; }
扫描二维码关注公众号,回复:
699446 查看本文章
10.打印链表
直接创建一个循环来打印链表的每个元素
//打印链表 @Override public void printLink() { // TODO Auto-generated method stub Node cur=this.first; for(;cur!=null;cur=cur.next) { System.out.println(cur.data); } System.out.println(); }