链表和双线链表
单链表
1.创建一个Node类
// head不能动,头节点作用是表示链表的头
private Node head;
// 在linkedList类写一个Node的成员内部类
private class Node {
private int data;
private Node next;
public Node(int data) {
this.data = data;
this.next = null;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
'}';
}
}
2.头插法
// 头插法
public void addFirst(int data) {
// 首先创建一个节点,要头插的结点
Node newNode = new Node(data);
if (head == null) {
head = newNode;
return;
}
newNode.next = head;
head = newNode;
}
3.尾插法
// 尾插法
public void addLast(int data) {
// 首先创建一个节点
Node newNode = new Node(data);
if (head == null) {
head = newNode;
return;
}
// head不能动,需要一个辅助指针temp,遍历完链表
Node temp = head;
while (temp.next != null) {
temp = temp.next;//遍历链表
}
temp.next = newNode;
}
4.指定位置插入
// 指定位置插入
public void addByOrder(int data, int position) {
// 首先创建一个节点
Node newNode = new Node(data);
if (position == 0) {
// 头插法
newNode.next = head;
head = newNode;
return;
}
// position是size的话就是尾插法
if (position==size()){
addLast(data);
return;
}
// head不能动,需要一个辅助指针temp找的要插入位置的亲一个结点即temp
Node temp = head;
int curPosition = 0;
while (temp.next != null && curPosition < position - 1) {
temp = temp.next;
curPosition++;
}
newNode.next = temp.next;
temp.next = newNode;
}
5.查找key是否在单链表中
// 查找key是否在单链表中
public boolean getKey(int key) {
if (head.next == null) {
System.out.println("链表为空~~~");
return false;
}
Node temp = head.next;
while (temp != null) {
if (temp.data == key) {
return true;
}
temp = temp.next;
}
return false;
}
6.链表长度
// 链表长度
public int size() {
Node temp = head;
int count = 0;
while (temp != null) {
count++;
temp = temp.next;
}
return count;
}
7.删除数据
// 删除数据
public boolean deleteByOrder(int key){
Node temp=head;
// 找到前一个节点
while (temp.next!=null){
if (temp.next.data==key){
temp.next=temp.next.next;
return true;
}
temp=temp.next;
}
return false;
}
8.打印链表
// 打印链表
public void display() {
Node temp = head;
while (temp != null) {
System.out.print(temp.data + " ");
temp = temp.next;
}
System.out.println();
}
9.查找链表中的倒数第index的结点
// 查找链表中的倒数第index的结点
// 接收head结点和一个index
// index表示是倒数第index个结点
// 先把链表从头到尾遍历,得到总长度size
// 得到size后,从链表的第一个开始遍历(size-index)个,就可以找到
// 如果找到了,返回该结点,否则返回null
public static HeroNode findLastIndexNode(HeroNode head, int index) {
if (head.next == null)
return null;
// 第一个遍历得到链表的长度
int sizes = size();
// 第二次遍历size-index位置,就是我们的倒数的第k个结点
// 做index的检验
if (index < 0 || index > sizes)
return null;
// 定义辅助变量,for循环定位倒数的index
HeroNode cur = head.next;//3-1=2
for (int i = 0; i < sizes - index; i++) {
cur = cur.next;
}
return cur;
}
10.单链表反转
// 将单链表反转
public void reverseList(HeroNode head) {
// 当前链表为空,或者只有一个节点,无需反转,直接返回
if (head.next == null || head.next.next == null)
return;
// 定义辅助变量,遍历原来的链表
HeroNode cur = head.next;
// 指向当前节点cur的下一个节点
HeroNode next= null;
// 定义哨兵结点方便给后面找到头节点的位置
HeroNode reverseHead = new HeroNode(-1, "", "");
// 遍历原来的链表,每遍历一个结点,将其取出,并放在新的链表reverseHead的最前端
while (cur != null) {
next = cur.next;//先暂时保存当前节点的下一个节点,后面需要使用
cur.next = reverseHead.next;//将cur的下一个结点指向新的链表的最前端
reverseHead.next = cur;//将cur连接到新的链表上
cur = next;//cur后移
}
// 将head.next指向reverseHead.next,实现单链表的反转
head.next = reverseHead.next;
}
11.逆序打印单链表
// 逆序打印单链表,用栈的数据结构
public void reversePrint(HeroNode head) {
if (head.next == null)
return;
// 创建栈,将各个节点压入栈中
Stack<HeroNode> stack = new Stack<>();
HeroNode cur = head.next;
// 入栈
while (cur != null) {
stack.push(cur);
cur = cur.next;//后移,便于压入下一个节点
}
// 出栈
while (stack.size() > 0) {
System.out.println(stack.pop());//先进后出
}
}
双向链表
双向链表的尾插法和修改和单链表一样
1.指定的位置插入
// 根据排名插入到指定的位置
// 如果有这个排名,添加失败,给出提示
public void addByOrder(HeroNode2 newHeroNode) {
// 头节点不能动,仍然通过一个辅助指针来帮助找到添加的位置
// 因为单链表,我们找到的temp是位于添加位置的前一个结点,否者插入不了
HeroNode2 temp = head;
boolean flag = false;// flag标志添加的编号,默认false
while (true) {
if (temp.next == null)//temp已经在链表最后了
break;
if (temp.next.no > newHeroNode.no)//位置找到,temp的后面插入,该节点在temp和temp.next之间
break;
else if (temp.next.no == newHeroNode.no) {//编号已经存在
flag = true;//编号存在
break;
}
temp = temp.next;//后移temp,遍历链表
}
// 判断flag的值
if (flag)//不能添加,编号已经存在
System.out.printf("准备插入的英雄编号%d已经存在,不能添加", newHeroNode.no);
else {
newHeroNode.next = temp.next;
temp.next = newHeroNode;
newHeroNode.pre = temp;
if (newHeroNode.next != null) {
newHeroNode.next.pre = newHeroNode;
}
}
}
2.删除数据
// 对于双向链表,直接找到要删除的结点即可,自我删除
public void delete(int no) {
if (head.next == null) {
System.out.println("链表为空,无法删除~~~");
return;
}
// 辅助指针temp
HeroNode2 temp = head.next;
boolean flag = false;//标志是否找到待删除结点
while (true) {
if (temp == null)//已经在链表的最后了
break;
if (temp.no == no) { //比较两节点的no
// 找到待删除结点的前一个结点temp
flag = true;
break;
}
temp = temp.next;//temp后移,遍历链表
}
// 判断flag
if (flag) {//找到
temp.pre.next = temp.next;
// 如果要删除的是最后一个节点,要temp.next是否为空,否则空指针异常
if (temp.next != null)
temp.next.pre = temp.pre;
} else {
System.out.printf("要删除的%d结点不存在\n", no);
}
}