有头单链表和无头单链表
- 无头单链表如下:
- 有头单链表
总结: - 有头结点表示第一个结点不保存数据,与其他数据节点区别开来
- 无头结点表示第一个节点保存数据,与其他节点除了位置不同,其余一模一样
两种链表在查询更改的方式是一样的,存在区别的是插入数据和删除数据
无头单链表
插入数据
- 中间节点插入数据
(1)找到要插入位置的前一个节点
(2)创造新节点
(3)新节点指向被插入节点的指针域
(4)前一个节点指向新节点
- 第一个节点之前添加数据
(1)创造新节点
(2)新节点指向第一个节点
(3)设置新节点为第一个节点
- 最后一个节点之前添加数据
已知:当前尾节点为tail
(1) 创建新节点
(2)尾节点tail指向新节点
(3)设置新节点为tail
删除数据
反转链表
- 原地反转
参考
无头单链表实现
// 无头单链表
public class Singlelist {
//链表可以没有头结点,不能没有头指针
private Node top; // 这里的top相当于第一个节点
private Node tail; // 用于尾部插入元素: 相当于最后一个车厢
private int length = 0;
public Singlelist() {
top = null; // 刚开始的时候一个节点都没有
}
/*
* empty()函数返回真(true)如果链表为空,否则返回假
* */
public boolean empty(){
return top == null; // 一个节点都没有
}
/*
* 获取list中元素的个数 size
* */
public int size(){
return length;
}
/*
* 在链表的尾部插入元素、
*
* * 当前程序中,top指向车尾, 每次遍历链表都是从车尾开始的。
* 如果离top越近就先出。 top指向最新生成的节点,先进先出, 尾插法
* */
public void push_back(int ele){
Node node = new Node();
node.setData(ele);
if (empty()){ // 如果一个节点都没有
top = node; // 那么就让头指针指向第一个节点: 这个节点的指针域为null,数据域为data、
tail = node; // 用于尾部插入元素
}else{
node.setNext(top); // 当前节点指向首节点
top = node; // 当前节点就变成了受节点
}
length++;
}
/*
* 在链表的首部插入元素:
* 头插法就是在单链表的节点插入操作中,
* 新的节点总是在前面,结果有点类似栈的先进后出
* */
public void push_front(int ele){
Node node = new Node();
node.setData(ele);
if (empty()){
tail = node;
top = node;
}else{
tail.setNext(node);
tail = node; // 尾节点后移动
}
length++;
}
public void reverse1(){
if (empty() || size() == 1) {
return;
}
Node pre = top; // top 一定不为空, 如果为空则已经返回了, 当前长度1
Node cur = pre.getNext(); // 不可能为空,因为如果长度为1也直接返回了,链表的长度至少为2
Node fur = cur.getNext(); // 可能为空
tail = pre;
pre.setNext(null);
while (cur != null){
cur.setNext(pre); // 指向前驱
pre = cur; // pre是不要了的,所以先去
cur = fur;
if (fur != null){ // fur不是最后一个节点
fur = fur.getNext();
}
// 如果fur == null, 那么cur == null, 就会跳出循环
}
top = pre;
}
/*
* 在链表的指定位置上插入元素
* */
public void insert(int pos, int ele){
if (pos == 0){
push_back(ele);
return;
}
if (pos == length){
push_front(ele);
return;
}
Node t = searchNode(pos - 1); // 找到当前位置的前一个节点
Node n = new Node();
n.setData(ele);
n.setNext(t.getNext()); // 新节点指向原来位置的节点
t.setNext(n); // 前一个节点指向新节点
length++;
}
// 从头节点开始查找第n个元素
public Node searchNode(int pos){
if (pos < 0 || pos > size() - 1){
System.out.println("超出索引范围");
return null ;
}
// 找到第n个元素
Node temp = top;
int i = 0;
while (i < pos){
temp = temp.getNext();
i++;
}
return temp;
}
/*
* 删除首节点的位置
* */
public void pop_back(){
if (empty()){
System.out.println("当前链表为空");
return;
}
top = top.getNext(); // 头指针向下移动
length--;
}
/*
* 删除尾节点
* */
public void pop_front(){
if (empty()){
System.out.println("当前链表为空");
return;
}
if (size() == 1){
clear();
return;
}
// 找到倒数第二个节点的位置
Node t = searchNode(size() - 2);
t.setNext(null);
length--;
}
/*
* 删除指定节点的位置
* */
public void pop_pos(int pos){
if (empty()){
System.out.println("当前链表为空");
return;
}
if (pos < 0 || pos > size() - 1){
System.out.println("超出索引");
return;
}
if (pos == 0){
pop_back();
return;
}
if (pos == size() - 1){
pop_front();
return;
}
// 指定节点的前一个节点
Node t = searchNode(pos - 1);
t.setNext(t.getNext().getNext());
length--;
}
// 删除链表中的所有元素 clear
public void clear(){
top = null;
length = 0;
}
public void showList(){
Node temp = top; // 建立一个临时指针,获取到头指针
while (temp != null){ // 只要头节点还是指向节点
System.out.print(temp.getData() + " -> ");
temp = temp.getNext(); // 临时节点移动到下一个节点位置
}
System.out.println();
}
}