链表实现
- 在我们数据结构中,单链表非常重要。它里面的数据元素是以结点为单位,每个结点是由数据元素的数据和下一个结点的地址组成,在java集合框架里面
LinkedList、HashMap(数组加链表)等等的底层都是用链表实现的。 - 下面是单链表的几个特点:
数据元素在内存中存放的地址是不连续的:单链表的结点里面还定义一个结点,它里面保存着下一个结点的内存地址,在实例化对象的时候,jvm会开辟不同内存空间,并且是不连续的。
添加效率高:添加一个元素时,先找到插入位置的前一个,只需要将1,2个元素的连接断开,将插入结点的next指向第一个元素的next(1),然后将第一个元素的next指向插入结点(2),
不用在挪动后面元素
删除效率高:删除一个元素时,先找到删除位置,将前一个的next指向删除位置的next,不用在挪动后面元素
查询效率低:查询的时候必须从头开始,依次遍历,而数组因为它的内存是连续的,可以直接通过索引查找。 - 下面通过代码来实现单链表结构:
/**
* @ClassName: TLinkedList
* @Description: 构建单项链表
* @author ENO
* @date 2021年1月12日
*
* @param <T>
*/
public class TLinkedList<T> {
// 链表头部
private Node head;
// 链表元素的个数
private int size;
public TLinkedList() {
head = null;
size = 0;
}
class Node {
// 下一个结点
private Node next;
// 结点的数据
private T t;
public Node(T t) {
this.t = t;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
/**
*
* @Title: addFirst
* @Description: 链表头部添加一个节点
* @param @param t
* @return void
* @throws
*/
public void addFirst(T t) {
Node node = new Node(t);
node.next = head;
head = node;
size++;
}
/**
*
* @Title: addMid
* @Description: 在链表中间添加一个元素
* @param @param t
* @return void
* @throws
*/
public void addMid(T t, int index) {
Node node = new Node(t);
Node mid = head;
for (int i = 0; i < index - 1; i++) {
mid = mid.next;
}
node.next = mid.next;
mid.next = node;
size++;
}
/**
*
* @Title: addLast
* @Description: 在链表尾部添加一个结点
* @param @param t
* @return void
* @throws
*/
public void addLast(T t) {
Node node = new Node(t);
Node last = head;
while (last.next != null) {
last = last.next;
}
last.next = node;
node.next = null;
size++;
}
/**
*
* @Title: removeFirst
* @Description: 删除头部节点
* @param
* @return void
* @throws
*/
public void removeFirst() {
head = head.next;
size--;
}
/**
*
* @Title: removeMid
* @Description: 删除链表的中间元素
* @param @param index
* @return void
* @throws
*/
public void removeMid(int index) {
Node mid = head;
if (index == 0) {
removeFirst();
return;
}
int j = 0;
Node qMid = head;
while (j < index) {
qMid = mid;
mid = mid.next;
j++;
}
qMid.next = mid.next;
size--;
}
/**
*
* @Title: removeLast
* @Description: 刪除尾部节点
* @param
* @return void
* @throws
*/
public void removeLast() {
Node mid = head;
Node qMid = head;
while (mid.next != null) {
qMid = mid;
mid = mid.next;
}
qMid.next = null;
size--;
}
/**
*
* @Title: get
* @Description: 获取链表指定下标的结点
* @param @param index
* @param @return
* @return Node
* @throws
*/
public Node get(int index) {
Node mid = head;
if (index == 0) {
return head;
}
int j = 0;
while (j < index) {
mid = mid.next;
j++;
}
return mid;
}
public static void main(String[] args) {
TLinkedList<String> linkedList = new TLinkedList<>();
linkedList.addFirst("hello1");
linkedList.addFirst("hello2");
linkedList.addFirst("hello3");
for (int i = 0; i < linkedList.size; i++) {
System.out.println(linkedList.get(i).getT());
}
// linkedList.removeLast();
// linkedList.removeFirst();
// linkedList.addLast("hello4");
linkedList.addMid("hello", 2);
System.out.println("--------------");
for (int i = 0; i < linkedList.size; i++) {
System.out.println(linkedList.get(i).getT());
}
}
}
栈(Stack)
-
一提到栈我们脑海就会浮现四个字“先进后出”,没错,它就是栈的最大特点。
-
栈的应用场景也非常多,比如将字符串反转、jvm里面的栈区等等。
-
栈里面的主要操作有:
push(入栈):将一个数据元素从尾部插入
pop(出栈):将一个数据元素从尾部删除
peek(返回栈顶元素):将栈顶元素的数据返回
相当于只有一个开口就是尾部,只能从尾进,从尾出 -
下面通过链表结构实现栈结构:
public class TStack<T> {
// 栈的头结点
private Node head;
// 栈的元素个数
private int size;
class Node {
// 下一个结点
private Node next;
// 结点的数据
private T t;
public Node(T t) {
this.t = t;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
public TStack() {
head = null;
size = 0;
}
/**
*
* @Title: push
* @Description: 入栈
* @param @param t
* @return void
* @throws
*/
public void push(T t) {
Node node = new Node(t);
if (size == 0) {
node.next = head;
head = node;
size++;
return;
}
if (size == 1) {
head.next = node;
node.next = null;
size++;
return;
}
Node lastNode = head;
while (lastNode.next != null) {
lastNode = lastNode.next;
}
lastNode.next = node;
node.next = null;
size++;
}
/**
*
* @Title: push
* @Description: 出栈
* @param @param t
* @return void
* @throws
*/
public T pop() {
if (size == 0) {
System.out.println("栈内无值");
return null;
}
if (size == 1) {
T t = head.getT();
head = null;
size--;
return t;
}
Node lastNode = head;
Node qNode = head;
while (lastNode.next != null) {
qNode = lastNode;
lastNode = lastNode.next;
}
T t = lastNode.getT();
qNode.next = null;
size--;
return t;
}
/**
*
* @Title: getSize
* @Description: 获取栈里面元素的个数
* @param @return
* @return int
* @throws
*/
public int getSize() {
return size;
}
/**
*
* @Title: peek
* @Description: 返回栈顶元素
* @param @return
* @return T
* @throws
*/
public T peek() {
if (size == 0) {
System.out.println("栈内无值");
return null;
}
if (size == 1) {
return head.getT();
}
Node lastNode = head;
while (lastNode.next != null) {
lastNode = lastNode.next;
}
return lastNode.getT();
}
public static void main(String[] args) {
TStack<String> stack = new TStack<>();
stack.push("hello1");
stack.push("hello2");
stack.push("hello3");
System.out.println("-------");
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
}
}
队列(Queue)
- 队列的特点也用“先进先出”四个字来概括。就是先进去的元素先输出出来。
- 我们常见的消息队列就是队列结构实现的。
- 队列的常见操作如下:
put(入队):将一个结点插入到尾部。
pop(出队): 将头结点的下一个结点作为头,然后将原来的头结点删除。 - 通过链表结构实现队列:
public class TQueue<T> {
// 头结点
private Node front;
// 尾结点
private Node tail;
// 队列中元素的个数
private int size;
class Node {
// 下一个结点
private Node next;
// 结点的数据
private T t;
public Node(T t) {
this.t = t;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public TQueue() {
front = tail = null;
}
/**
*
* @Title: put
* @Description: 入队
* @param @param t
* @return void
* @throws
*/
public void put(T t) {
Node node = new Node(t);
if (size == 0) {
front = tail = node;
size++;
return;
}
Node lastNode = front;
while (lastNode.next != null) {
lastNode = lastNode.next;
}
lastNode.next = node;
tail = node;
size++;
}
/**
*
* @Title: pop
* @Description: 出队
* @param @return
* @return T
* @throws
*/
public T pop() {
if (size == 0) {
System.out.println("队列中无值");
return null;
}
T t = front.getT();
front = front.next;
size--;
return t;
}
public static void main(String[] args) {
TQueue<String> tQueue = new TQueue<>();
tQueue.put("Hello1");
tQueue.put("Hello2");
tQueue.put("Hello3");
for (int i = 0; i < 3; i++) {
System.out.println(tQueue.pop());
}
}
}