1.链表介绍
1.1链表是有序的列表,但是它在内存中是存储如下:
1) 链表是以节点的方式来存储,是链式存储
2) 每个节点包含 data 域, next 域:指向下一个节点.
3) 如图:发现链表的各个节点不一定是连续存储.
4) 链表分带头节点的链表
和
没有头节点的链表
,根据实际的需求来确定
1.2单链表(带头结点) 逻辑结构示意图如下:
1.3代码实现
package com.ws;
public class SingleLinkedList {
//设置链表头
Student head = new Student(0,"","");
/**
* 添加元素 在尾部添加
* @param student
*/
public void add(Student student) {
Student temp = head;
//遍历找到链表的尾部 在尾部添加数据
while (true) {
if(temp.next == null) {
break;
}
temp = temp.next;
}
temp.next = student;
}
/**
* 根据学号从小到大添加元素
* @param student
*/
public void addOrderByAsc(Student student) {
Student temp = head;
//flag标识该学号是否存在
boolean flag = false;
while(true) {
if(temp.next == null) {
//链表为空 或 所有数据的no都比要插入的数据的no小 直接插在末尾
break;
}
//找到刚好大于自己的 前一个数据 插在temp和temp.next中间
if(temp.next.no > student.no) {
break;
}
if(temp.next.no == student.no) {
//该学号已存在
flag = true;
}
temp = temp.next;
}
//如果学号已存在 返回提示
if(flag) {
System.out.println("学号为:"+student.no+"的学生已存在不能再添加~");
} else {
student.next = temp.next;
temp.next = student;
}
}
/**
* 根据学号修改信息 *学号不可改!!
*/
public void updateByNo(Student student) {
if(head.next == null) {
System.out.println("链表为空无法修改~");
return;
}
Student temp = head;
//flag标识是否找到该学号的节点
boolean flag = false;
while(true) {
if(temp == null) {
break;
}
if(temp.no == student.no) {
//找到
flag = true;
break;
}
temp = temp.next;
}
if(flag) {
temp.name = student.name;
temp.className = student.className;
} else {
System.out.println("学号为:"+student.no+"的学生没有找到~");
}
}
/**
* 根据id查找节点
* @param no
*/
public void queryByNo(int no) {
if(head.next == null) {
System.out.println("链表为空~");
}
Student temp = head;
boolean flag = false;
while(true) {
if(temp == null) {
break;
}
if(temp.no == no) {
flag= true;
break;
}
temp = temp.next;
}
if(flag) {
System.out.println(temp);
} else {
System.out.println("学号为:" + no + "的学生没有找到~");
}
}
/**
* 查看链表所有元素
*/
public void queryLinkedList() {
//判断链表是非为空
if(head.next == null) {
System.out.println("链表为空~");
return;
}
Student temp = head.next;
while(true) {
if(temp == null) {
break;
}
System.out.println(temp);
temp = temp.next;
}
}
/**
* 根据学号删除节点
* @param no
*/
public void deleteByNo(int no) {
Student temp = head;
//flag标识是否找到该学号的节点
boolean flag = false;
while(true) {
if(temp.next == null) {
break;
}
if(temp.next.no == no) {
flag = true;
break;
}
temp = temp.next;
}
if(flag) {
temp.next = temp.next.next;
} else {
System.out.println("删除失败!学号为" + no + "的学生没有找到~");
}
}
}
class Student {
//no为唯一标识
public int no;
public String name;
public String className;
public Student next;
//构造器
public Student(int no, String name, String className) {
this.no = no;
this.name = name;
this.className = className;
}
@Override
public String toString() {
return "Student{" +
"no=" + no +
", name='" + name + '\'' +
", className='" + className +
'}';
}
}
测试代码:
package com.ws;
public class Test1 {
public static void main(String[] args) {
Student stu1 = new Student(1,"张三","物联网18-3");
Student stu2 = new Student(2,"李四","物联网18-3");
Student stu3 = new Student(3,"王五","物联网18-1");
Student stu4 = new Student(4,"盾山","物联网18-4");
Student stu5= new Student(5,"虞姬","物联网18-6");
SingleLinkedList linkedList = new SingleLinkedList();
// linkedList.add(stu1);
// linkedList.add(stu5);
// linkedList.add(stu2);
// linkedList.add(stu4);
// linkedList.add(stu3);
//升序添加
linkedList.addOrderByAsc(stu1);
linkedList.addOrderByAsc(stu5);
linkedList.addOrderByAsc(stu2);
linkedList.addOrderByAsc(stu4);
linkedList.addOrderByAsc(stu3);
linkedList.queryLinkedList();
System.out.println("~~~~~~~");
//修改节点
// Student newStu4 = new Student(4, "公孙离", "软件18-4");
// linkedList.updateByNo(newStu4);
//删除节点
linkedList.deleteByNo(4);
linkedList.queryLinkedList();
//按学号查询节点
linkedList.queryByNo(5);
}
}
扩展:
package com.ws;
public class Util {
/**
* 获取单链表有效节点(忽略头节点)
* @param head
* @return
*/
public static int getLength(Student head) {
int count = 0;
if(head.next == null) {
return count;
}
Student temp = head.next;
while (temp != null) {
count ++;
temp = temp.next;
}
return count;
}
/**
* 获取倒数第k个节点的值
* @param head 头节点
* @param index 倒数第几个节点
* @return
*/
public static void getDaoshuIndex(Student head, int index) {
Student temp = head.next;
int length = getLength(head);
if(head.next == null) {
System.out.println("该头节点的链表为空");
}
if(index > length ) {
System.out.println("k > 该链表长度");
return;
}
if(index < 0) {
System.out.println("k不可以小于0");
return;
}
for(int i = 0; i < length - index; i++) {
temp = temp.next;
}
System.out.println(temp);
}
/**
* 将单链表反转
* @param head
*/
public static void reverse(Student head) {
if(head.next == null) {
System.out.println("该链表为空~");
}
//辅助变量 用来遍历链表
Student temp = head.next;
//指向temp的下一个节点
Student next = null;
//创建一个新头 遍历一个节点就插入一个节点 且都插在最前面
Student newhead = new Student(0, "", "");
while (temp != null) {
next = temp.next;
temp.next = newhead.next;
newhead.next = temp;
temp = next;
}
head.next = newhead.next;
}
/**
* 从尾部到头部打印单链表
* 本方法用的数组 用stack也可
* @param head
*/
public static void printTail2Head(Student head) {
if(head.next == null) {
System.out.println("链表为空~");
}
int length = getLength(head);;
//把数据放到数组 按下标实现到放
Student stuArr[] = new Student[length];
Student temp = head.next;
for(int i = length; i > 0; i-- ) {
stuArr[i-1] = temp;
temp = temp.next;
}
//遍历数组
for (Student stu : stuArr) {
System.out.println(stu);
}
}
/**
* 合并两个单链表 保证有序性
* @param head1
* @param head2
* @return 合并后的有序单链表
*/
public static SingleLinkedList mergeTwoLinkedList(Student head1,Student head2) {
// Student newhead = new Student(0,"","");
SingleLinkedList linkedList = new SingleLinkedList();
Student temp1 = head1.next;
Student temp2 = head2.next;
Student next = temp1;
while(temp1 != null) {
next = temp1.next;
linkedList.addOrderByAsc(temp1);
temp1 = next;
// linkedList.addOrderByAsc(temp1);
// temp1 = temp1.next;
}
while(temp2 != null) {
next = temp2.next;
linkedList.addOrderByAsc(temp2);
temp2 = next;
}
return linkedList;
}
}
双向链表的结构与单向链表相似,也就是多了个pre可以指向前一个节点。