单链表操作(Java实现)

单链表

用一组地址任意的存储单元存放线性表中的数据元素。
数据域 (数据元素)+ 指针域 (指示后继元素存储位置)= 结点
在这里插入图片描述
在这里插入图片描述

单链表创建与输出

package danlianbiao;

public class LinkList {
public Node head;//头结点
public Node current;//当前结点

//方法:向链表中添加数据
public void add(int data) {
 //判断链表为空的时候
 if (head == null) {//如果头结点为空,说明这个链表还没有创建,那就把新的结点赋给头结点
 head = new Node(data);
 current = head;
 } else {
 //创建新的结点,放在当前节点的后面(把新的结点合链表进行关联)
 current.next = new Node(data);
 //把链表的当前索引向后移动一位
 current = current.next; //此步操作完成之后,current结点指向新添加的那个结点
 }
}

//方法:遍历链表(打印输出链表。方法的参数表示从节点node开始进行遍历
public void print(Node node) {
 if (node == null) {
 return;
 }

current = node;
 while (current != null) {
 System.out.println(current.data);
 current = current.next;//指向下一个结点;
 }
} 

class Node {
//注:此处的两个成员变量权限不能为private,因为private的权限是仅对本类访问。
 int data; //数据域
 Node next;//指针域

 public Node(int data) {
 this.data = data;
}
}



public static void main(String[] args) {
LinkList list = new LinkList();
//向LinkList中添加数据
 for (int i = 0; i <20; i++) {
 list.add(i);
 }

 list.print(list.head);// 从head节点开始遍历输出
 int a=list.getLength(list.head);

}

}

获取单链表长度

//方法:获取单链表的长度
public int getLength(Node head) {
 if (head == null) {
 return 0;
 }

 int length = 0;
 Node current = head;
 while (current != null) {
 length++;
 current = current.next;
 }

 return length;
}

查找单链表中倒数第k个结点

这里我们可以有几种思路,一种是遍历全部,得出链表长度,然后直接输出第size-k个结点,但是这个不够全面,我们要考虑到k=0和k超出链表长度的情况,所以我们可以声明两个结点型的变量first和second,首先让first和second都指向第一个结点,然后让second往后移动k-1个位置,再让整体向后移,直到second移到最后一个结点,这时first就是所要找的结点

 public Node findLastNode(Node head, int k) {
 if (k == 0 || head == null) {
  return null;
  }
 
  Node first = head;
  Node second = head;
 
 //让second结点往后挪k-1个位置
  for (int i = 0; i < k - 1; i++) {
  System.out.println("i的值是" + i);
  second = second.next;
  if (second == null) { //说明k的值已经大于链表的长度了
  //throw new NullPointerException("链表的长度小于" + k); //我们自己抛出异常,给用户以提示
   return null;
  }
 }
 
  //让first和second结点整体向后移动,直到second走到最后一个结点
  while (second.next != null) {
  first = first.next;
  second = second.next;
  }
  //当second结点走到最后一个节点的时候,此时first指向的结点就是我们要找的结点
 return first;
 }
 

查找单链表中的中间结点

算法与上述类似,只不过这次second移两步,first移一步;直到second移到最后一个结点处;

 //方法:查找链表的中间结点
 public Node findMidNode(Node head) {
 
 if (head == null) {
  return null;
 }
 
 Node first = head;
 Node second = head;
 //每次移动时,让second结点移动两位,first结点移动一位
 while (second != null && second.next != null) {
  first = first.next;
  second = second.next.next;
 }
 
 //直到second结点移动到最后一个结点时,此时first指针指向的位置就是中间结点的位置
  return first;
 }
 

合并两个有序的单链表,合并之后的链表依然有序

//两个参数代表的是两个链表的头结点
public Node mergeLinkList(Node head1, Node head2) {
	/*
	 * 首先判断两个合并的链表是否为空,或者其中一个为空
	 * 然后新链表的头结点和当前结点初始为空,
	 * 依次扫描head1和head2的值,比较当前元素的值,将小的放进新链表中,
	 * 直到其中一个链表为空,再将另一个链表剩余存放进新链表
	 */

if (head1 == null && head2 == null) { //如果两个链表都为空
 return null;
}
 if (head1 == null) {
 return head2;
}
 if (head2 == null) {
 return head1;
}

Node head; //新链表的头结点
 Node current; //current结点指向新链表 
// 一开始,我们让current结点指向head1和head2中较小的数据,得到head结点
 if (head1.data < head2.data) {
 head = head1;
 current = head1;
 head1 = head1.next;
 } else {
 head = head2;
 current = head2;
 head2 = head2.next;
}

 while (head1 != null && head2 != null) {
 if (head1.data < head2.data) {
  current.next = head1; //新链表中,current指针的下一个结点对应较小的那个数据
  current = current.next; //current指针下移
  head1 = head1.next;
 } else {
 current.next = head2;
  current = current.next;
  head2 = head2.next;
 }
 }

 //合并剩余的元素
 while (head1 != null) { //说明链表2遍历完了,是空的
 current.next = head1;
 head1=head1.next;
 current=current.next;
 }

while (head2 != null) { //说明链表1遍历完了,是空的
 current.next = head2;
 head2=head2.next;
 current=current.next;
}

 return head;
}

测试:

 LinkList list1 = new LinkList();
 LinkList list2 = new LinkList();
 //向LinkList中添加数据
 for (int i = 0; i < 4; i++) {
  list1.add(i);
  }
 
 for (int i = 5; i < 8; i++) {
  list2.add(i);
 }
 
 LinkList list3 = new LinkList();
 list3.head = list3.mergeLinkList(list1.head, list2.head); //将list1和list2合并,存放到list3中
 
 list3.print(list3.head);// 从head节点开始遍历输出

单链表的反转

 //方法:链表的反转
 public Node reverseList(Node head) {
 
 //如果链表为空或者只有一个节点,无需反转,直接返回原链表的头结点
  if (head == null || head.next == null) {
  return head;
 }
 
 Node current = head;
 Node next = null; //定义当前结点的下一个结点
  Node reverseHead = null; //反转后新链表的表头
 
 while (current != null) {
  next = current.next; //暂时保存住当前结点的下一个结点,因为下一次要用
 
  current.next = reverseHead; //将current的下一个结点指向新链表的头结点
  reverseHead = current; 
 
  current = next; // 操作结束后,current节点后移
 }
 
 return reverseHead;
 }
 

从尾到头打印单链表

 public void reversePrint(Node head) {
 
 
  if (head == null) {
  return;
  }
 reversePrint(head.next);
 System.out.println(head.data);
 }

判断单链表是否有环

 //方法:判断单链表是否有环
 public boolean hasCycle(Node head) {
 
  if (head == null) {
  return false;
  }
 
  Node first = head;
  Node second = head;
 
  while (second != null) {
  first = first.next; //first指针走一步
  second = second.next.next; second指针走两步
 
  if (first == second) { //一旦两个指针相遇,说明链表是有环的
   return true;
  }
 }
 
  return false;
 }

删除链表中的重复结点

/**
     * 删除重复节点
     */
    public void deleteDuplecate(Node head) {
        Node p = head;
        while (p != null) {
            Node q = p;
            while (q.next != null) {
                if (p.data == q.next.data) {
                    q.next = q.next.next;
                } else
                    q = q.next;
            }
            p = p.next;
        }

    }

删除链表中指定值的结点

public Node removeElements(Node head,int data)
{
	/*
	 * 这里要判断头结点是否为要删除的值,
	 * 判断完后,要有一个当前结点和当前结点的前一个结点
	 * 当前结点遍历,遇到指定值,使pre.next=current.next,完成删除,没遇到就是pre=pre.next;
	 * 接着current=current.next移到下一个结点,最后返回头结点
	 */
	while(head!=null)
	{
		if(head.data!=data)
		{
			break;
		}
		head=head.next;
	}
	
	Node current=head;
	Node pre=head;
	while(current!=null)
	{
		if(current.data==data)
		{
			pre.next=current.next;
		}
		else {
			pre=current;
		}
		current=current.next ;
		
	}
	return head;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱技术的小小林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值