方法一:通过调用Stack这个类来实现
1.了解 栈 是一种只能在一端进行插入或删除操作的线性表 并且是先入后出的(也是后入先出)
2.下面我们先了解一下栈的基本操作:
Stack stack=new Stack();//这是创建一个Stack类对象并赋值给Stack类的stack变量
stack.empty()//是判断栈是否为空,若为空则返回true
System.out.println(stack.empty());
push//是入栈
stack.push("字符串入栈");
peek()//取栈顶值(不出栈)
System.out.println(stack.peek());//输出栈顶的值
pop//出栈
stack.pop();//出栈一个栈顶元素
search()//可以查询元素在栈的位置
3.下面我们来想一下原理:通过调用Stack这个类的push方法往栈中存入一系列数,想要实现增加一个数,就简单的在push一个就可以;若是想在某一特定数的前面加入这个数,首先需要讲特定数之后的先取出,然后在放入增加的数,然后再把取出的数放回。
删、改也都是同样的原理。
4.下面我们用代码实现一下栈中删除某一特定数的方法:
public static void main(String[] args)
{
Stack stack=new Stack();//创建一个新的Stack对象,并赋值给Stack类型的stack变量
System.out.println(stack.empty());//判断新建的stack栈是否为空
for(int i=0;i<10;i++)//往栈里输入[0,1,2,3,4,5,6,7,8,9]
{
stack.push(new Integer(i));
}
System.out.println(stack);//输出栈
del(stack,3);//调用下面del方法
del(stack,8);
}
public static void del(Stack stack,int target)
{
int site=stack.search(target);//通过search方法查询目标数,返回的是以1开始的下标数
Object[] a= new Object[site];//创建一个新数组,长度为栈内要取出数的长度
for(int i=0;i<site;i++)//从栈取出的赋给数组,数组最后一个数即为要删除的数
{
a[i]=stack.pop();
}
for(int j=site-2;j>=0;j--)//从数组后倒数第二位开始往栈中存,倒数第一位是要删除的
{
stack.push(a[j]);
}
System.out.println(stack);
}
方法二:也可以通过数组来实现
1.把数组想象成栈,那么就是要在数组尾进行存入和取出的操作,头不动。
2.这里就说一下思路:通过两个数组,一个模拟成栈的形式,一个用来存放取出的数据。再自己定义两个方法,一个往数组存,一个从数组取出。
方法三:通过链表(也就是一个个的结点)的形式实现栈
一、用一个例子来体现链表形式实现栈的模式:
1.首先我们先建立一个单结点
public class MyStack<T> {//<T>代表任意引用类型 泛型//定义一个单结点
private T data;//定义成私有的 通过get set的取值赋值方法调用 避免被随意更改其中的值
private MyStack<T> next;
//调用get\set函数
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public MyStack<T> getNext() {
return next;
}
public void setNext(MyStack<T> next) {
this.next = next;
}
@Override
public String toString() {//不加的话,输出的为地址
return "MyStack [data=" + data + ", next=" + next + "]";
}
}
2.写一个学生类
public class Student {
//实例域 若用public会破坏封装,谁都可以访问, 用来存放要操作的数据
private int stuNum;
private String name;
private String otherInfo;
//调用get set方法
public int getStuNum() {
return stuNum;
}
public void setStuNum(int stuNum) {
this.stuNum = stuNum;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOtherInfo() {
return otherInfo;
}
public void setOtherInfo(String otherInfo) {
this.otherInfo = otherInfo;
}
@Override
public String toString() {
return "Student [stuNum=" + stuNum + ", name=" + name + ", otherInfo=" + otherInfo + "]";
}
}
3.通过学生数组,想象每一个都是一个单结点。然后栈,需要有一个固定的头(linkBanji),和一个随着加入数据而移动的指针flag——永远指向最后一个数据(因为栈是后入先出,所以只需要一个指针,指向最后一个数据结点即可)。随着每加入一个数据,新建一个单结点,并通过next连起来,再移动flag指针指向新加入的数据。
public class TestClass {
public static void main(String[] args)
{
String[] studentNames=new String[]//定义数组并赋值
{
"xiao1","xiao2","xiao3","xiao4","xiao5","xiao6","xiao7","xiao8"
};
MyStack<Student> linkBanji=new MyStack<Student>();//头
MyStack<Student> flag=linkBanji;//随着移动的一个指针
//通过循环把数组中的数据放入栈中,每放入一个新的数据就在堆中新建一块区域
for( int i = 0; i < studentNames.length; i++ )
{
Student stu = new Student();
//给stu赋值
flag.setData(stu);
stu.setName( studentNames[i] );
stu.setStuNum(i);
stu.setOtherInfo("我序号为" + ( i + 1 ) );
if(i<studentNames.length-1)//小于的时候证明数组中还有数据没有存放进栈中
{
flag.setNext(new MyStack<Student>());//通过next指向新建的区域
flag=flag.getNext;//flag通过next的指向 指向新建的区域
}
}
System.out.println(linkBanji);//输出这个栈的数据
}
}
图解:更直观理解如何通过单结点形成链表
二、实现链表栈的输出:
先写一个出栈入栈的方法
package test;
import pag.MyStack;
public class StackClass<T> {//<T>是泛型
private MyStack<T> que; //栈只要用头标就行
public MyStack<T> getQue() {
return que;
}
public void setQue(MyStack<T> que) {
this.que = que;
}
public void add( MyStack<T> add ){//入栈
if( que == null ){//空的时候就直接放入第一个头标处即可
que = add;
}else{
add.setNext(que);//不空时,add放入que的下一个结点(setNext(que)表示que的下一结点)
que = add;//挪动头标位置
}
}
public MyStack<T> pop(){//出栈
MyStack<T> result = que;//赋值
if( que != null ){
que = que.getNext();//不为空,que往后挪动
}
return result;
}
public void look(){
System.out.println(que.toString());//调用MyStack里的toString()
}
}
主函数
public class TestClass {
public static void main(String[] args)
{
String[] studentNames=new String[]//定义数组并赋值
{
"xiao1","xiao2","xiao3","xiao4","xiao5","xiao6","xiao7","xiao8"
};
StackClass<Student> que=new StackClass<Student>();//建立que变量 头
//通过循环把数组中的数据放入栈中,每放入一个新的数据就在堆中新建一块区域
for( int i = 0; i < studentNames.length; i++ )
{
MyStack<Student> flag=new MyStack<Student>();
Student stu = new Student();
//给stu赋值
flag.setData(stu);
stu.setName( studentNames[i] );
stu.setStuNum(i);
stu.setOtherInfo("我序号为" + ( i + 1 ) );
que.add(flag);//讲flag放入que中
if(i==3)//条件符合时输出,因为这是栈所以刚存进去就输出。(这里跟队列有所区别)
{
MyStack<Student> as=que.pop();//出栈
if(as==null){
System.out.println("空了");
break;
}else{System.out.println(as.getData().getName())}
}
}
for(;;){//循环输出栈内数据
MyStack<Student> as=que.pop();
if(as==null)
{
System.out.println("空了");
break;
}else{System.out.println(as.getData().getName())}
}
}
}