本文主要是基于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++;
}
2.根据下标删除元素
首先要判断下标是否合法(下标必须要在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;
}
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();
}