单链表

概念

  链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。

特点

  1. 链表是以节点的方式来存储,是链式存储

  2. 每个节点包含 data 域, next 域:指向下一个节点.

  3. 链表的各个节点不一定是连续存储.

代码

对象

//每个学生就是一个节点
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();

 从尾到头打印单链表

  1. 将链表进行反转,然后打印,但这样效率低,要求也没有让改变链表结构
  2. 利用栈先进后出的原理,通过遍历把节点存储在栈里,然后打印
/**
   * 从尾到头打印单链表
   * @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();

posted @ 2021-07-28 20:55  翻蹄亮掌一皮鞋  阅读(63)  评论(0)    收藏  举报