今天的内容是把昨天的栈和队列补上
今天学了循环链表、双向链表、循环双向链表,以及昨天的栈和队列
- 栈
栈是一种后进先出的结构,对于栈的用处我一直有疑惑,但是我思考以后,想,栈的用途与它的特点是离不开的,后进先出的特点,优再先进去的数,最后才可以处理,就像再数学算法中的小括号()的,只有当匹配到一对括号时,才可以运算,这种思想恰好可以推及到程序编写
先上栈信息
信息包括节点数据(也就是内容)
以及一个构造方法
public class MyStack {
int[] elements;
public MyStack() {
elements = new int[0];
}
压栈方法
//压栈
public void push(int element) {
//创建一个新的数组,长度是原数组加一
int[] newArr = new int[elements.length + 1];
//将原数组中的所有的数据转到新数组中,因为循环的范围是原数组
//长度,所以新数组的最后一个是空的
for (int i = 0; i < elements.length; i++) {
newArr[i] = elements[i];
}
//赋值新数组的最后一个数
newArr[elements.length] = element;
//更新原数组
elements = newArr;
}
取出栈顶元素(获得元素,并出栈)
//取出栈顶元素
public int pop() {
//先判定栈是否为空
if (elements.length == 0)
throw new RuntimeException("栈为空");
/*
根据后进先出的规则,将最后进栈的数据
也就是下标为数组长度减一的数取出
*/
int element = elements[elements.length - 1];
//创建新数组,长度为原数组长度减一
int[] newArr = new int[elements.length - 1];
//数组赋值,并将最后一个数出栈
for (int i = 0; i < newArr.length; i++) {
newArr[i] = elements[i];
}
//更新原数组
elements = newArr;
return element;
}
查看栈顶元素(不出栈)
//查看栈顶元素
public int peek() {
if (elements.length == 0)
throw new RuntimeException("栈为空");
return elements[elements.length - 1];
}
判定栈是否为空
//判定栈是不是空
public boolean isEmpty() {
return elements.length == 0;
}
到这里栈的操作完成了
下面是栈的完整代码
/**
* @program: ForStudyDataStruct
* @description:
* @author: 张成灬玺
* @create: 2020-01-28 19:18
***/
public class MyStack {
int[] elements;
public MyStack() {
elements = new int[0];
}
//压栈
public void push(int element) {
//创建一个新的数组,长度是原数组加一
int[] newArr = new int[elements.length + 1];
//将原数组中的所有的数据转到新数组中,因为循环的范围是原数组
//长度,所以新数组的最后一个是空的
for (int i = 0; i < elements.length; i++) {
newArr[i] = elements[i];
}
//赋值新数组的最后一个数
newArr[elements.length] = element;
//更新原数组
elements = newArr;
}
//取出栈顶元素
public int pop() {
//先判定栈是否为空
if (elements.length == 0)
throw new RuntimeException("栈为空");
/*
根据后进先出的规则,将最后进栈的数据
也就是下标为数组长度减一的数取出
*/
int element = elements[elements.length - 1];
//创建新数组,长度为原数组长度减一
int[] newArr = new int[elements.length - 1];
//数组赋值,并将最后一个数出栈
for (int i = 0; i < newArr.length; i++) {
newArr[i] = elements[i];
}
//更新原数组
elements = newArr;
return element;
}
//查看栈顶元素
public int peek() {
if (elements.length == 0)
throw new RuntimeException("栈为空");
return elements[elements.length - 1];
}
//判定栈是不是空
public boolean isEmpty() {
return elements.length == 0;
}
}
- 队列
队列可以与栈做对比,队列是一种先进先出的结构,在操作系统中作业排队可以理解为队列,因为队列与栈有很多相似的地方,所以这里不多赘述,直接上完整代码
package demo2;
/**
* @program: ForStudyDataStruct
* @description:
* @author: 张成灬玺
* @create: 2020-01-28 19:50
***/
public class MyQueue {
int[] elements;
public MyQueue() {
elements = new int[0];
}
//入队
public void add(int element) {
int[] newArr = new int[elements.length + 1];
for (int i = 0; i < elements.length; i++) {
newArr[i] = elements[i];
}
newArr[newArr.length - 1] = element;
elements = newArr;
}
//出队
public int poll() {
if (elements.length == 0)
throw new RuntimeException("队列为空");
int element = elements[0];
int[] newArr = new int[elements.length - 1];
for (int i = 0; i < newArr.length; i++) {
newArr[i] = elements[i + 1];
}
elements = newArr;
return element;
}
}
- 循环链表
循环链表,就比较有意思了,特点是在链表的末尾的节点的下一个节点链接上了头节点,我认为这样的好处弥补了单链表只能向后查找的缺点
首先是循环链表的节点信息
public class LoopNode {
//节点内容
int date;
//下一个节点
LoopNode next = this;
//构造方法
public LoopNode(int date) {
this.date = date;
}
删除当前节点的下一个节点(原理:将当前节点的下一个节点的下一个节点链接给当前节点的下一个节点)
//删除节点
public void removeNode() {
//获取到当前节点的下下个节点
LoopNode nextNode = next.next;
//将当前节点的下一个节点链接上上面获取的下下个节点
this.next = nextNode;
}
插入节点(原理:将当前节点的下一个节点赋给参数节点的下一个节点,并将参数节点赋给当前节点的下一个节点)
//插入节点
public void insert(LoopNode node) {
LoopNode doubleNextNode = this.next;
this.next = node;
node.next = doubleNextNode;
}
还有两个方法与算法无关,下面给出完整代码
/**
* @program: ForStudyDataStruct
* @description:
* @author: 张成灬玺
* @create: 2020-01-28 20:30
***/
public class LoopNode {
//节点内容
int date;
//下一个节点
LoopNode next = this;
//构造方法
public LoopNode(int date) {
this.date = date;
}
//删除节点
public void removeNode() {
//获取到当前节点的下下个节点
LoopNode nextNode = next.next;
//将当前节点的下一个节点链接上上面获取的下下个节点
this.next = nextNode;
}
//插入节点
public void insert(LoopNode node) {
LoopNode doubleNextNode = this.next;
this.next = node;
node.next = doubleNextNode;
}
//获取下一个节点
public LoopNode getNext() {
return this.next;
}
//获取节点数据
public int getDate() {
return this.date;
}
}
- (循环)双向链表(一起写了)
双向循环链表,有两个关键的地方
1、双向:意思指每个节点都有两个指针域(之前单向的节点只能指向后一个节点),这两个指针域分别指向前一个节点(pre)和后一个节点(next),这样的好处是即可以访问后继也可以访问前驱
2、循环:意思指尾节点的后继(next)指向了头节点,头节点的前驱(pre)指向了尾节点
先上节点信息(DoubleLoopNode pre是前驱指针,将this赋给它意思是循环,后继同)
public class DoubleLoopNode {
//上一个节点
DoubleLoopNode pre = this;
//下一个节点
DoubleLoopNode next = this;
//节点内容
int data;
public DoubleLoopNode(int data) {
this.data = data;
}
增加节点(原理:先获取当前节点的后继节点,在将当前节点的后继指针指向参数节点,参数节点的前驱指向当前节点,参数节点的后继指向前面获取的后继节点)
//增加节点
public void after(DoubleLoopNode node) {
//原来的下一个节点
DoubleLoopNode nextNext = next;
//把新节点做完当前节点的下一个节点
this.next = node;
//把当前节点做新节点的前一个节点
node.pre = this;
//让原来的下一个节点做为新节点的下一个节点
node.next = nextNext;
//让原来的下一个节点的上一个节点为新节点
nextNext.pre = node;
}
最难理解的就是添加节点了,懂了以后其他的都不难了,下面是完整代码
/**
* @program: ForStudyDataStruct
* @description:
* @author: 张成灬玺
* @create: 2020-01-29 20:12
***/
public class DoubleLoopNode {
//上一个节点
DoubleLoopNode pre = this;
//下一个节点
DoubleLoopNode next = this;
//节点内容
int data;
public DoubleLoopNode(int data) {
this.data = data;
}
//增加节点
public void after(DoubleLoopNode node) {
//原来的下一个节点
DoubleLoopNode nextNext = next;
//把新节点做完当前节点的下一个节点
this.next = node;
//把当前节点做新节点的前一个节点
node.pre = this;
//让原来的下一个节点做为新节点的下一个节点
node.next = nextNext;
//让原来的下一个节点的上一个节点为新节点
nextNext.pre = node;
}
//下一个节点
public DoubleLoopNode getNext() {
return this.next;
}
//上一个节点
public DoubleLoopNode getPre() {
return this.pre;
}
//获取数据
public int getData() {
return this.data;
}
}
今晚的学习效率不高,按理说我应该是喜欢计算机的啊,我可以疯狂的敲代码从早晨到晚上一个星期,看来我现在还是比较浮躁
我想成为一个温柔的人,因为曾被温柔的人那样对待,深深了解那种被温柔相待的感觉。
——夏目友人帐