单链表
概念
链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
特点
-
链表是以节点的方式来存储,是链式存储
-
每个节点包含 data 域, next 域:指向下一个节点.
-
链表的各个节点不一定是连续存储.
代码
对象
//每个学生就是一个节点
class Student{
public int stuNo;
public String name;
//指向下一个节点
public Student next;
public Student(int stuNo, String name) {
this.stuNo = stuNo;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"stuNo=" + stuNo +
", name='" + name + '\'' +
'}';
}
}
不考虑编号排序,直接添加
//管理学生
class StudentLinkedList{
//初始化头节点,头节点不能动,不存放具体的数据
private final Student head = new Student(0,"");
/**
* 不考虑编号排序,直接找到当前链表最后的节点,将最后节点的next指向新添加的节点
* 因为头节点不能动,不然无法遍历,需要一个辅助节点
* @param student 添加的对象
*/
public void add(Student student){
Student temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = student;
}
public void show(){
//判断链表是否为空
if(head.next == null){
return;
}
//辅助节点
Student temp = head.next;
while (temp != null) {
System.out.println(temp);
//将节点后移,不然是死循环
temp = temp.next;
}
}
}
测试
public static void main(String[] args) { StudentLinkedList studentLinkedList = new StudentLinkedList(); Student stu1 = new Student(1, "1号"); Student stu2 = new Student(2, "2号"); Student stu3 = new Student(4, "4号"); Student stu4 = new Student(3, "3号"); studentLinkedList.add(stu1); studentLinkedList.add(stu2); studentLinkedList.add(stu3); studentLinkedList.add(stu4); studentLinkedList.show(); }
按照编号顺序添加
public void addByNo(Student student){ Student temp = head; //用来标识要添加的学生是否已经存在 boolean flag = false; while (true){ if(temp.next == null){ break; } if(temp.next.stuNo > student.stuNo){ break; } if(temp.next.stuNo == student.stuNo){ flag = true; break; } temp = temp.next; } if(flag){ System.out.printf("要添加的学生编号%d 已经存在\n",temp.stuNo); }else { student.next = temp.next; temp.next = student; } }
测试
StudentLinkedList studentLinkedList = new StudentLinkedList(); Student stu1 = new Student(1, "1号"); Student stu2 = new Student(2, "2号"); Student stu3 = new Student(4, "4号"); Student stu4 = new Student(3, "3号");
studentLinkedList.addByNo(stu1);
studentLinkedList.addByNo(stu2);
studentLinkedList.addByNo(stu4);
studentLinkedList.addByNo(stu3);
studentLinkedList.addByNo(stu3);
studentLinkedList.show();
修改
public void update(Student student){ if(head.next == null){ System.out.println("链表无数据"); return; } Student temp = head.next; //判断要修改的对象是否存在 boolean flag = false; while (true){ if(temp == null){ break; } if(temp.stuNo == student.stuNo){ flag = true; break; } temp = temp.next; } if(flag){ temp.name = student.name; }else { System.out.printf("学生编号为%d 的学生不存在",student.stuNo); } }
测试
StudentLinkedList studentLinkedList = new StudentLinkedList(); Student stu1 = new Student(1, "1号"); Student stu2 = new Student(2, "2号"); Student stu3 = new Student(4, "4号"); Student stu4 = new Student(3, "3号"); // studentLinkedList.add(stu1); // studentLinkedList.add(stu2); // studentLinkedList.add(stu3); // studentLinkedList.add(stu4); studentLinkedList.addByNo(stu1); studentLinkedList.addByNo(stu2); studentLinkedList.addByNo(stu4); studentLinkedList.addByNo(stu3); studentLinkedList.addByNo(stu3); studentLinkedList.show(); Student stu = new Student(1,"111"); studentLinkedList.update(stu); System.out.println("修改后的数据"); studentLinkedList.show();
删除
public void delete(int stuNo){ if(head.next == null){ System.out.println("链表无数据"); } Student temp = head; //判断要删除的学生是否存在 boolean flag = false; while (true){ if(temp.next == null){ break; } if(temp.next.stuNo == stuNo){ flag = true; break; } temp = temp.next; } if(flag){ //这样要删除的对象没有任何引用指向它,虚拟机就会把它删掉 temp.next = temp.next.next; } }
测试
StudentLinkedList studentLinkedList = new StudentLinkedList(); Student stu1 = new Student(1, "1号"); Student stu2 = new Student(2, "2号"); Student stu3 = new Student(4, "4号"); Student stu4 = new Student(3, "3号"); // studentLinkedList.add(stu1); // studentLinkedList.add(stu2); // studentLinkedList.add(stu3); // studentLinkedList.add(stu4); studentLinkedList.addByNo(stu1); studentLinkedList.addByNo(stu2); studentLinkedList.addByNo(stu4); studentLinkedList.addByNo(stu3); studentLinkedList.addByNo(stu3); studentLinkedList.delete(1); studentLinkedList.show();
求单链表中有效节点的个数
由于StudentLinkedList的head属性是私有的,给它填上get方法
/** * 头节点不算数 * @param head 链表的头节点 */ public static int getLength(Student head){ if(head.next == null){ return 0; } int length = 0; Student temp = head.next; while (temp != null) { length++; temp = temp.next; } return length; }
测试
StudentLinkedList studentLinkedList = new StudentLinkedList(); Student stu1 = new Student(1, "1号"); Student stu2 = new Student(2, "2号"); Student stu3 = new Student(4, "4号"); Student stu4 = new Student(3, "3号"); // studentLinkedList.add(stu1); // studentLinkedList.add(stu2); // studentLinkedList.add(stu3); // studentLinkedList.add(stu4); studentLinkedList.addByNo(stu1); studentLinkedList.addByNo(stu2); studentLinkedList.addByNo(stu4); studentLinkedList.addByNo(stu3); System.out.println(getLength(studentLinkedList.getHead()));
查找单链表中的倒数第k个节点
/** * 查找单链表中的倒数第k个节点 * @param head 链表的头节点 * @param index 倒数第几个 * @return 有数据就返回,没有就返回null */ public static Student findLastIndexNode(Student head,int index){ if(head.next == null){ return null; } int length = getLength(head); if(index < 0 || index > length){ return null; } Student temp = head.next; for (int i = 0; i < length - index; i++){ temp = temp.next; } return temp; }
测试
StudentLinkedList studentLinkedList = new StudentLinkedList(); Student stu1 = new Student(1, "1号"); Student stu2 = new Student(2, "2号"); Student stu3 = new Student(4, "4号"); Student stu4 = new Student(3, "3号"); // studentLinkedList.add(stu1); // studentLinkedList.add(stu2); // studentLinkedList.add(stu3); // studentLinkedList.add(stu4); studentLinkedList.addByNo(stu1); studentLinkedList.addByNo(stu2); studentLinkedList.addByNo(stu4); studentLinkedList.addByNo(stu3); Student lastIndexNode = findLastIndexNode(studentLinkedList.getHead(), 2); System.out.println(lastIndexNode);
单链表的反转
/** * @param head 链表的头节点 * 单链表的反转 */ public static void reversalList(Student head){ //如果链表没有节点或者只有一个节点,直接return if(head.next == null || head.next.next == null){ return; } Student student = new Student(0,""); Student next; Student temp = head.next; while (temp != null){ next = temp.next; temp.next = student.next; student.next = temp; temp = next; } head.next = student.next; }
测试
StudentLinkedList studentLinkedList = new StudentLinkedList(); Student stu1 = new Student(1, "1号"); Student stu2 = new Student(2, "2号"); Student stu3 = new Student(4, "4号"); Student stu4 = new Student(3, "3号"); // studentLinkedList.add(stu1); // studentLinkedList.add(stu2); // studentLinkedList.add(stu3); // studentLinkedList.add(stu4); studentLinkedList.addByNo(stu1); studentLinkedList.addByNo(stu2); studentLinkedList.addByNo(stu4); studentLinkedList.addByNo(stu3); reversalList(studentLinkedList.getHead()); studentLinkedList.show();
从尾到头打印单链表
- 将链表进行反转,然后打印,但这样效率低,要求也没有让改变链表结构
- 利用栈先进后出的原理,通过遍历把节点存储在栈里,然后打印
/** * 从尾到头打印单链表 * @param head 链表的头节点 */ public static void reversalPrint(Student head){ if(head.next == null){ return; } Stack<Student> stack = new Stack<>(); Student temp = head.next; while (temp != null){ stack.add(temp); temp = temp.next; } while (stack.size() > 0){ System.out.println(stack.pop()); } }
测试
StudentLinkedList studentLinkedList = new StudentLinkedList(); Student stu1 = new Student(1, "1号"); Student stu2 = new Student(2, "2号"); Student stu3 = new Student(4, "4号"); Student stu4 = new Student(3, "3号"); // studentLinkedList.add(stu1); // studentLinkedList.add(stu2); // studentLinkedList.add(stu3); // studentLinkedList.add(stu4); studentLinkedList.addByNo(stu1); studentLinkedList.addByNo(stu2); studentLinkedList.addByNo(stu4); studentLinkedList.addByNo(stu3); reversalPrint(studentLinkedList.getHead());
合并两个有序的单链表,合并之后的链表依然有序
/** * 合并两个有序的单链表,合并之后的链表依然有序 * @param head1 第一个链表的头节点 * @param head2 第二个链表的头节点 */ public static void combine(Student head1,Student head2){ if(head1.next == null || head2 == null){ return; } Student temp = head1.next; Student cur = head2.next; Student next = null ; while (cur != null){ while (true){ if(temp.next == null || temp.next.stuNo > cur.stuNo){ next = cur.next; cur.next = temp.next; temp.next = cur; break; } temp = temp.next; } cur = next; } }
测试
Student stu5 = new Student(5, "5号");
Student stu7 = new Student(7, "7号");
Student stu9 = new Student(9, "9号");
Student stu11 = new Student(11, "11号");
StudentLinkedList studentLinkedList1 = new StudentLinkedList();
studentLinkedList1.addByNo(stu5);
studentLinkedList1.addByNo(stu7);
studentLinkedList1.addByNo(stu9);
studentLinkedList1.addByNo(stu11);
Student stu6 = new Student(6, "6号");
Student stu8 = new Student(8, "8号");
Student stu10 = new Student(10, "10号");
Student stu12 = new Student(12, "12号");
StudentLinkedList studentLinkedList2 = new StudentLinkedList();
studentLinkedList2.addByNo(stu6);
studentLinkedList2.addByNo(stu8);
studentLinkedList2.addByNo(stu10);
studentLinkedList2.addByNo(stu12);
combine(studentLinkedList1.getHead(),studentLinkedList2.getHead());
studentLinkedList1.show();