【数据结构】-带头结点的链表操作

最近在学习数据结构,对链表的理解也仅仅停留在书本上。现就链表的手写代码记录如下,新手上路避免不了错误的出现,还望批评指正。

单链表带头结点与不带头结点有何区别?

带头结点的优点

  • 链表的第一个结点不存储任何数据,仅仅作为链表存在的标志。
  • 插入/删除第一个存储数据的结点比较方便。
  • 空表和非空表的操作比较统一。

带头结点对链表进行以下的处理

带头结点与不带头结点的操作相类似,只是在考虑是否为空表上的处理略有差异

  • 插入 头插法、尾插法、中间插入
  • 删除 清除链表、删除第一个值为str、删除所有值为str
  • 反转 将链表反转

1-插入

插入的思想:申请一个结点,该结点的指针指向要插入位置的下一个结点。随后插入位置的上一个结点指向该结点(次序不能倒置)。当然尾插法就比较容易,链表的最后一个位置指向此申请的结点即可。

  • 头插法及尾插法的代码如下
	//头插法
	public void headadd(String str){
		 Lnode temp=new Lnode();
		 temp.data=str;
		 temp.next=head.next;
		 head.next=temp;
	}
	//尾插法
	public void endadd(String str){
			if(head.next==null){
			Lnode temp=new Lnode();
			temp.data=str;
			head.next=temp;
		}
		Lnode p=head.next;
		while(p.next!=null){
			p=p.next;
		}
		Lnode temp=new Lnode();
		temp.data=str;
		p.next=temp;		
	}

头插法不需要判定是否为空,尾插法需要判定是否为空。同时尾插法需要遍历。

  • 中间插入的代码操作如下
//将str1插入到结点(结点的`data` 为str)之前。
	public void add(String str1,String str){
		Lnode p=head.next;
		Lnode q=p;
		 while(q != null && str .equals(q.data)!=true){//这里最好不要用q.data==str
	            p = q;
	            q = q.next;
	        }
	        if(q == head.next){
	        	Lnode temp=new Lnode();
	        	temp.data=str1;
	        	temp.next=q;
	            head.next = temp;
//	            add(str1,str);//如果将此处与下处打开,则就是将所有的str之前均加一个str1
	        }
	        else if(q != null){
	        	Lnode temp=new Lnode();
	        	temp.data=str1;
	        	temp.next=q;
	            p.next = temp;
//	            add(str1,str);//如果将此处打开,则就是将所有的str之前均加一个str1
	        }else{
	            return;
	        }
	}

其实中间插入与尾插法有类似的地方,就是都需要遍历。

2-删除

删除链表中的某个数据,也需要遍历操作。

  • 下面介绍两种删除操作
//方法一  删除操作
public void delete(String str){
		Lnode q = head.next;
        Lnode p = q;
        while(q != null && str .equals(q.data)!=true){
            p = q;
            q = q.next;
        }
        if(q == head.next){
            head.next = q.next;
            q.next = null;
            q = null;
            delete(str);
        }
        else if(q != null){
            p.next = q.next;
            q.next = null;
            q = null;
            delete(str);
        }else{
            return;
        }
        }

方法一是递归的遍历操作。假设链表为a->b->c->d->e,我们要删除c,那么必须要找到b才能够进行删除。如果删除所有c,那么就需要从头开始递归操作。工作量大,代码也不好写。那么如何缩短工作量,并且减少代码呢?

	//方法二     删除链表中所有为str的结点
	public void delete(String str){
		Lnode p=head.next;
		Lnode q=p;
		while(p!=null){
			if(p.data.equals(str)){
				p.data=p.next.data;
				p.next=p.next.next;								
			}
			else
				p=p.next;
		}		
	}

假设链表为a->b->c->d->e,如果我们要删除 c,我们可以先遍历到c,然后将c的下一个结点(d)的值赋给b,然后在用指针指向e。此方法一次遍历即可删除所有c。

  • 清除链表
	public void clear(){
		Node temp= new Node();
		while(head!=null){
			temp=head;
			head=head.next;
			temp=null;
			
		}
	}

链表的清除可以用头结点的指针的的指向来进行删除操作。

3-反转
public void reverse(){
		Lnode p=head.next;
		head.next=null;//如果不指定 head.next为空,则会出现双倍的结点。
		while(p!=null){
			Lnode q=new Lnode();
			q.data=p.data;
			p=p.next;
			q.next=head.next;
			head.next=q;
		}		
	}

带头结点的链表反转,将一个指针指向头结点的后一个结点,并将头结点指向空。后面就是一个头插法的插入操作。

总结

无论是带头结点还是不带头结点,所考虑的核心问题都差不多。
带头结点的单链表操作注意一下几个要点。

  • 头插法比较容易些,尾插法比较麻烦需要一次完整的遍历。
  • 删除操作,注意注意遍历结点时要存储前一个结点,或者用第二种删除操作(一次遍历即可)。
  • 插入/删除操作掌握的差不多后,其余的打印、空表、获得单向链表倒数第i个结点、获取单向链表环的长度等方法,基本由这些方法演变出来的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值