基于Java实现不带头节点的双向链表的操作

本文主要是基于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;
	}

扫描二维码关注公众号,回复: 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();
	}

猜你喜欢

转载自blog.csdn.net/l_x_y_hh/article/details/79982520