教程学习地址:
https://www.bilibili.com/video/BV1E4411H73v
稀疏数组的处理方法是:
记录数组一共有几行几列,有多少个不同的值
把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
流程:正常的二维数组—>稀疏数组—>保存到磁盘中—>将磁盘中的数据还原成稀疏数组
package com.bear.稀疏数组;
import java.io.*;
/**
* <简述>
* <详细描述>
*
* @author LiuShanshan
* @version $Id$
*/
public class SparsearryTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
System.out.println("二维数组:");
// 生成二维数组 行 8 ,列7
int charArray[][] = new int[8][7];
// 1代表黑棋
charArray[1][2] = 1;
// 2代表蓝旗
// 没有赋值的为0
charArray[2][3] = 2;
charArray[4][3] = 3;
int sum = 0;
for (int[] hang : charArray) { // 2维数组变1维数组
for (int i : hang) {
if(i != 0){
sum ++;
}
System.out.printf("%d\t", i);
}
System.out.printf("\n");
}
System.out.println("=======================");
System.out.println("稀疏数组:");
// 生成散列数组 已知只会有3列,现在需要确实有几行
int sparseArray[][] = new int[sum + 1][3];
sparseArray[0][0] = 8;
sparseArray[0][1] = 7;
sparseArray[0][2] = sum;
int count = 0;
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 7; j++){
if(charArray[i][j] != 0){
count ++;
sparseArray[count][0] = i;
sparseArray[count][1] = j;
sparseArray[count][2] = charArray[i][j];
}
}
}
for (int[] ints : sparseArray) {
for (int anInt : ints) {
System.out.printf("%d\t", anInt);
}
System.out.printf("\n");
}
// 稀疏数组反推到二维数组
System.out.println("=======================");
System.out.println("散列数组反推到二维数组");
int thrustArray[][] = new int[sparseArray[0][0]][sparseArray[0][1]];
for (int i = 1; i < sparseArray.length; i++) {
thrustArray[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
}
for (int[] ints : thrustArray) {
for (int anInt : ints) {
System.out.printf("%d\t",anInt);
}
System.out.printf("\n");
}
// 将稀疏数组保存到磁盘上
// 将数据导入到磁盘中
stream(thrustArray);
// 将磁盘上的稀疏数组还原回来
System.out.println("==================");
System.out.println("磁盘中还原数据:");
stream();
}
// 保存数据到文件中
public static void stream(int[][] ob) throws IOException {
FileOutputStream fos = new FileOutputStream("c:\\javas\\map.data");//字节流
ObjectOutputStream oos = new ObjectOutputStream(fos);//对象输出流
oos.writeObject(ob);//存到磁盘上,序列化
// FileInputStream fis = new FileInputStream("c:\\javas\\map.data");
// ObjectInputStream ois = new ObjectInputStream(fis);//对象输入流
// System.out.println(ois.readObject());//读的时候,反序列化
}
// 从文件中获取数据
public static void stream() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("c:\\javas\\map.data");
ObjectInputStream ois = new ObjectInputStream(fis);//对象输入流
int[][] ints = (int[][]) ois.readObject(); //读的时候,反序列化
for (int[] anInt : ints) {
for (int i : anInt) {
System.out.printf("%d\t" , i);
}
System.out.printf("\n");
}
}
}
package com.bear.队列;
import java.util.Scanner;
/**
* <简述> 环形数组模拟队列
* <详细描述>
*
* @author LiuShanshan
* @version $Id$
*/
public class QueueTest{
public static void main(String[] args) {
// 测试
System.out.println("测试数组模拟环形队列的案例~~~");
//创建一个环形队列
CirciQueue queue=new CirciQueue(5);// 说明设置4,其队列的有效数据最大是3
char key ; //接收用户输入
Scanner scanner=new Scanner(System.in);//
boolean loop=true;
//输出一个菜单
while(loop){
System.out.println("s(show):显示队列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加数据到队列");
System.out.println("g(get):从队列取出数据");
System.out.println("h(head):查看队列头的数据");
key=scanner.next().charAt(0);//接收一个字符
switch(key){
case's':
queue.show();
break;
case'a':
System.out.println("输出一个数");
int value=scanner.nextInt();
queue.add(value);
break;
case'g'://取出数据
try{
int res=queue.get();
System.out.printf("取出的数据是%d\n",res);
}catch(Exception e){
//TODO:handleexception
System.out.println(e.getMessage());
}break;
case'e':
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出");
}
}
// 环形队列
class CirciQueue{
// 最大容量
private int maxSize ;
// 最下面数据的下标(包含开始元素),从0开始
private int front;
// 最上面数据的上标 + 1(不包含结束元素), 从0开始
private int real;
// 环形数组
private int[] queueArray;
// 1、构造函数,赋值初始值
CirciQueue(int maxSize){
this.maxSize = maxSize;
this.queueArray = new int[this.maxSize];
}
// 2、判断容器是否为空
private boolean notEmpty(){
return this.real == this.front;
}
// 3、容量是否已满
private boolean notFull(){
return (real + 1)% maxSize == front;
}
// 4、将数据放入环形数组中
public void add(int i){
if(notFull()){
System.out.println("容器已满,请先消费");
}else{
// 数据放入
this.queueArray[real] =i;
// real向后移动,这里需要考虑取模(余)(如果real正好在最上面,而front不等于0,并且可以放值,那么就需要将real放在最下面)
this.real = (real +1) % maxSize; // 取模
}
}
// 5、拿取数据 从下往上拿
public int get(){
// 是否容器为空
if(notEmpty()){
System.out.println("容器为空,请添加数据");
return -1;
}
int i = queueArray[front];
front = (front +1) % maxSize; // 取模
return i;
}
// 显示环形队列中的值
public void show(){
// 是否容器为空
if(notEmpty()){
System.out.println("容器为空,请添加数据");
}else{
// 循环次数为真实的有值的数据长度
for(int i = front; i < front + getRealLength(); i ++){
// 当前值,要取模
int i1 = queueArray[i % maxSize]; // 取模
System.out.printf("queueArray[%s]的值为:%s", queueArray[i % maxSize], i1);
}
}
}
// 获取真实的长度
private int getRealLength(){
// real在front上面 todo 这一部分重点看 取模
return (maxSize + real - front)% maxSize;
}
}
环形数组组成队列,重要是观察3个值:maxSize(最大容量),real(尾部数据+1的索引),front(开头数据的索引),不管是算容器是否满,计算真实的数据长度,显示容器中的值,将数据放在容器中等都需要使用到取模,需要取模之后计算。
package com.bear.线性结构.单链表;
/**
* <简述>
* <详细描述>
*
* @author LiuShanshan
* @version $Id$
*/
public class SingleLinkedListDemo {
public static void main(String[] args) {
// 测试
SingleLinked singleLinked = new SingleLinked();
singleLinked.addByNo(new HeroNode(1, "宋江"));
singleLinked.addByNo(new HeroNode(4, "林冲"));
singleLinked.addByNo(new HeroNode(2, "卢俊义"));
singleLinked.addByNo(new HeroNode(3, "吴用"));
singleLinked.addByNo(new HeroNode(3, "吴用2"));
singleLinked.show();
}
}
// 单链表 处理类
class SingleLinked{
// head信息,在链表的第一个,不能变动
private HeroNode heroNodeHeard = new HeroNode(0, "");
// 添加
public void addByNo(HeroNode heroNode){
// 添加辅助节点
HeroNode temp = heroNodeHeard;
boolean isRep = false;
while (true){
// 当前节点next为null,退出
if(temp.next == null){
break;
}
// 当前节点next值的no值大于传入进来的heroNode中的no值(因为是从小到大排序),则退出
if(temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){
isRep = true;
}
temp = temp.next;
}
if(isRep){
System.out.println("有重复数据,报错.");
}else{
// 到了这里,temp中的next就应该放入参heroNode
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//显示
public void show(){
if(heroNodeHeard.next == null){
System.out.println("没有添加数据");
}else{
// 头信息不能动
HeroNode temp = heroNodeHeard.next;
while (true){
System.out.println(temp);
if(temp.next == null){
break;
}
temp = temp.next;
}
}
}
}
// 类
class HeroNode{
// 编号
public int no;
// 名称
public String name;
// 指向下一个元素的对象
public HeroNode next;
HeroNode(int no, String name){
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
// 显示长度 heroNodeHeard 为头节点
public int getLength() {
// next没值返回0
if(heroNodeHeard.next == null){
return 0;
}
// next有值进行循环
int size = 0;
HeroNode temp = heroNodeHeard.next;
while (true){
size ++;
if(temp.next != null){
temp = temp.next;
}else{
break;
}
}
return size;
}
// 查找单链表中的倒数第k个结点
public HeroNode selectReciIndex(int index){
// index是否合理 // index不能比长度大
if(index <= 0 || index > getLength()){
return null;
}
// 用长度减去index,得到应该查询第几条数据
int shouldSelectLength = getLength() - index + 1;
// 进行循环,查找到数据
HeroNode temp = heroNodeHeard.next;
for (int i = 1; i < shouldSelectLength; i++){
temp = temp.next;
}
return temp;
}
思路:单项链表倒转,实现原理:创建一个单链表倒叙数据,将链表循环,每一次循环的数据作为倒转链表的next值,倒叙链表的next值作为传过来的数据的next值
// 倒转链表
public void reverse(){
// 定义一个辅助变量,帮助我们遍历原来的链表
HeroNode cur = heroNodeHeard.next;
HeroNode next = null; // 指向当前节点[cur]的下一个节点
// 倒转数组
HeroNode reverseHead = new HeroNode(0, "");
// 遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead的最前端
while(cur != null){
next = cur.next;
// 将倒转数据下面的next给cur,因为cur将会成为倒转数组里面的第一个数据
cur.next = reverseHead.next;
reverseHead.next = cur;
cur = next;
}
// 赋值,将revers中的next放入head的next中, head.next = reverse.next
heroNodeHeard.next = reverseHead.next;
}
1、可以使用1.3.3.3的方式(不推荐)
2、使用stack(栈)的方式(先进后出)
// 链表倒叙输出 方法1:使用倒转链表的方法;方法2:使用栈的方式stack
public void stack(){
Stack<HeroNode> heroNodeStack = new Stack<HeroNode>();
HeroNode next = heroNodeHeard.next;
while(next != null){
heroNodeStack.push(next);
next = next.next;
}
while (heroNodeStack.size()>0){
System.out.println(heroNodeStack.pop());
}
}
package com.bear.线性结构.单链表;
import java.util.Stack;
/**
* <简述>
* <详细描述>
*
* @author LiuShanshan
* @version $Id$
*/
public class SingleLinkedListDemo {
public static void main(String[] args) {
// 测试
SingleLinked singleLinked = new SingleLinked();
singleLinked.addByNo(new HeroNode(1, "宋江"));
singleLinked.addByNo(new HeroNode(4, "林冲"));
singleLinked.addByNo(new HeroNode(2, "卢俊义"));
singleLinked.addByNo(new HeroNode(3, "吴用"));
singleLinked.addByNo(new HeroNode(3, "吴用2"));
singleLinked.show();
// 显示长度
int length = singleLinked.getLength();
System.out.println(length);
// 查询出倒数第2个元素的数据
HeroNode heroNode = singleLinked.selectReciIndex(4);
System.out.println(heroNode);
// ================================================将链表倒转===============
System.out.println("================================================将链表倒转===============");
// 单项链表倒转,实现原理:创建一个单链表倒叙数据,将链表循环,每一次循环的数据作为倒转链表的next值,
// 倒叙链表的next值作为传过来的数据的next值
singleLinked.reverse();
singleLinked.show();
//============================链表倒叙打印=================
System.out.println("============================链表倒叙打印=================");
singleLinked.stack();
}
}
// 单链表 处理类
class SingleLinked{
// head信息,在链表的第一个,不能变动
private HeroNode heroNodeHeard = new HeroNode(0, "");
// 添加
public void addByNo(HeroNode heroNode){
// 添加辅助节点
HeroNode temp = heroNodeHeard;
boolean isRep = false;
while (true){
// 当前节点next为null,退出
if(temp.next == null){
break;
}
// 当前节点next值的no值大于传入进来的heroNode中的no值(因为是从小到大排序),则退出
if(temp.next.no > heroNode.no){
break;
}else if (temp.next.no == heroNode.no){
isRep = true;
}
temp = temp.next;
}
if(isRep){
System.out.println("有重复数据,报错.");
}else{
// 到了这里,temp中的next就应该放入参heroNode
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//显示
public void show(){
if(heroNodeHeard.next == null){
System.out.println("没有添加数据");
}else{
// 头信息不能动
HeroNode temp = heroNodeHeard.next;
while (true){
System.out.println(temp);
if(temp.next == null){
break;
}
temp = temp.next;
}
}
}
// 显示长度 heroNodeHeard 为头节点
public int getLength() {
// next没值返回0
if(heroNodeHeard.next == null){
return 0;
}
// next有值进行循环
int size = 0;
HeroNode temp = heroNodeHeard.next;
while (true){
size ++;
if(temp.next != null){
temp = temp.next;
}else{
break;
}
}
return size;
}
// 查找单链表中的倒数第k个结点
public HeroNode selectReciIndex(int index){
// index是否合理 // index不能比长度大
if(index <= 0 || index > getLength()){
return null;
}
// 用长度减去index,得到应该查询第几条数据
int shouldSelectLength = getLength() - index + 1;
// 进行循环,查找到数据
HeroNode temp = heroNodeHeard.next;
for (int i = 1; i < shouldSelectLength; i++){
temp = temp.next;
}
return temp;
}
// 倒转链表
public void reverse(){
// 定义一个辅助变量,帮助我们遍历原来的链表
HeroNode cur = heroNodeHeard.next;
HeroNode next = null; // 指向当前节点[cur]的下一个节点
// 倒转数组
HeroNode reverseHead = new HeroNode(0, "");
// 遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead的最前端
while(cur != null){
next = cur.next;
// 将倒转数据下面的next给cur,因为cur将会成为倒转数组里面的第一个数据
cur.next = reverseHead.next;
reverseHead.next = cur;
cur = next;
}
// 赋值,将revers中的next放入head的next中, head.next = reverse.next
heroNodeHeard.next = reverseHead.next;
}
// 链表倒叙输出 方法1:使用倒转链表的方法;方法2:使用栈的方式stack
public void stack(){
Stack<HeroNode> heroNodeStack = new Stack<HeroNode>();
HeroNode next = heroNodeHeard.next;
while(next != null){
heroNodeStack.push(next);
next = next.next;
}
while (heroNodeStack.size()>0){
System.out.println(heroNodeStack.pop());
}
}
}
// 类
class HeroNode{
// 编号
public int no;
// 名称
public String name;
// 指向下一个元素的对象
public HeroNode next;
// 指向上一个元素的对象
public HeroNode pre;
HeroNode(int no, String name){
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
package com.bear.线性结构.单项环形表;
import java.beans.beancontext.BeanContext;
import java.lang.invoke.LambdaConversionException;
/** 单项环形表----约瑟夫问题
* <简述> 一个对象赋值给另一个对象,另一个对象可以改变自己的结构,但是如果改变自己的值,那么一个对象也会改变,这是因为
* 他们指向内存的值的内存地址是同一个
* <详细描述>
*
* @author LiuShanshan
* @version $Id$
*/
public class Josepfu {
public static void main(String[] args) {
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
// 添加a
for(int i = 1; i<=4; i++){
circleSingleLinkedList.add(new Boy(i));
}
// ==============查询=============
System.out.println(" ==============查询=============");
circleSingleLinkedList.show();
// =============取出数据===============
System.out.println("=============取出数据===============");
circleSingleLinkedList.delete(1,2);
}
}
class CircleSingleLinkedList{
private Boy first = null;
// 增
public void add(Boy needBoy){
if(first == null){
first = needBoy;
first.next = first;
}
// 给first后面增加数据
Boy cusboy = first.next;
while (true){
if(cusboy.next == first){
needBoy.next = first;
cusboy.next = needBoy;
break;
}
cusboy = cusboy.next;
}
System.out.println("添加成功");
}
// 出圈
/**
*<简述>
*<详细描述>
* @author Liushanshan
* @param startNo 从哪条数据开始
* @param nums 间隔几个数据进行取出
* @return void
*/
public void delete(int startNo, int nums){
// 判断当前first是否为空
// 开始取出,需要cub(当前辅助节点); later(cub只有的一个节点)
Boy later = first;
// 给later赋值为first的最后一个值
while(true){
if(later.next == first){
break;
}
later = later.next;
}
// 开始位置为nums-1 ,确认开始循环的位置
for (int i = 0; i < startNo - 1; i++){
first = first.next;
later = later.next;
}
// 开始循环,每次循环次数为nums-1
while (true){
// 退出
if(later == first){
break;
}
for(int j = 0; j < nums -1; j++){
first = first.next;
later = later.next;
}
// 要出圈的小孩
System.out.printf("\n要出去的数据:%s", first);
// 因为已经出圈了,所以将later里面的next设置为first.next
first = first.next;
later.next = first;
}
System.out.printf("\n最后一个数据为:%s", later);
}
// 改 改变里面的数据最简单,不实现
//查
public void show(){
// 判断first是否为空
if(first == null){
System.out.println("数据为空,请添加数据");
return;
}
// 循环查询,结束语句为cub.next = first
Boy cub = first;
while (true){
if(first.next == first){
System.out.printf("当前只有一个数据为:%s", first);
break;
}
if(cub.next == first){
break;
}
System.out.printf("\n开始打印数据:%s", cub);
cub = cub.next;
}
System.out.printf("\n最后一个数据为:%s", cub);
}
}
class Boy{
public int no;
public Boy next;
Boy(int no){
this.no = no;
}
@Override
public String toString() {
return "Boy{" +
"no=" + no +
'}';
}
}
栈的原理遵循先进后出的原理,所以可以用数组进行模拟
package com.bear.线性结构.栈;
/** 栈的实现使用数组的方式,遵循先进后出的原则
* <简述>
* <详细描述>
*
* @author LiuShanshan
* @version $Id$
*/
public class StackTest {
public static void main(String[] args) {
Stack stack = new Stack(3);
stack.show();
System.out.println("===============添加数据==================");
stack.add(1);
stack.add(2);
stack.add(3);
stack.show();
}
}
class Stack {
// 数组
private int[] arry ;
// top
private int top;
// 放入的值
private int value;
Stack(int length){
this.arry = new int[length];
this.top = -1;
}
//是否满
private boolean isFull(){
return arry.length == top + 1;
}
// 是否为空
private boolean isEntity(){
return top == -1;
}
// 添加
public void add (int value){
// 判断是否已满
if(isFull()){
System.out.println("容量已满");
return;
}
// 放入值,top+1
this.value = value;
top ++;
arry[top] = this.value;
}
// 查,显示
public void show(){
// 是否为空
if(isEntity()){
System.out.println("容器为空,请先添加数据");
return;
}
// 显示
for(int i = top; i>= 0; i--){
System.out.printf("\n输出数据:%s", arry[i]);
}
}
}
package com.bear.线性结构.后缀表达式;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* <简述> 后缀表达式(逆波兰表达式)
* <详细描述>1、逆波兰表达式计算 2、中缀表达式转后缀表达式(逆波兰表达式)
*
* @author LiuShanshan
* @version $Id$
*/
public class PolandNotation {
public static void main(String[] args) {
// (3+4)×5-6对应的后缀表达式就是3 4 + 5 × 6 -
// 2.逆波兰表达式计算
List<String> exp = new ArrayList<>();
exp.add("3");
exp.add("4");
exp.add("+");
exp.add("5");
exp.add("*");
exp.add("6");
exp.add("-");
System.out.printf("计算出来的值为:%s", calculate(exp));
// 1.中缀表达式转后缀表达式
}
// 逆波兰表达式,计算出值
public static int calculate(List<String> exp){
Stack<Integer> integerStack = new Stack<>();
if(exp.size() == 0){
System.out.println("没有需要计算的数据");
}
// 加入栈,并且计算,计算逻辑为:压入数据,遇到运算符的时候,取出最上面的2个数据,进行计算,将计算出来的值放回栈,直到运算到
// 栈中只剩下一个值为止
for (String s : exp) {
// 如果是数字,则直接放入栈
if(s.matches("\\d+")){
integerStack.push(Integer.valueOf(s));
}else{
// 如果是符号,则从栈中取出2个数据进行计算,然后再放回栈
Integer pop2 = integerStack.pop();
Integer pop1 = integerStack.pop();
//判断当前是 + - * / 哪一个
if("+".equals(s)){
integerStack.push(pop1 + pop2);
}else if ("-".equals(s)){
integerStack.push(pop1 - pop2);
}else if("*".equals(s)){
integerStack.push(pop1 * pop2);
}else if("/".equals(s)){
integerStack.push(pop1/pop2);
}
}
}
return integerStack.pop();
}
}
todo 后面再写
总结:递归总的来说是将递归的方法,放在栈里面,每一个方法都是独立开来的,因为是栈,所以先放后拿,从最上面方法开始计算。
package com.bear.线性结构.递归;
/** 迷宫问题(小球找路)
* <简述>
* <详细描述>
*
* @author LiuShanshan
* @version $Id$
*/
public class Maze {
public static void main(String[] args) {
// 定义规则,定义一个二维数组,给里面的增加1代表墙
int[][] map = new int[8][7];
for(int i = 0; i<8; i++){
map[i][0] = 1;
map[i][6] = 1;
}
for(int j = 0; j< 7; j++){
map[0][j] = 1;
map[7][j] = 1;
}
// 第4行,第二列,第三列为1
map[3][1] = 1;
map[3][2] = 1;
// // 循环打印,看是不是组成了一个墙
// for(int i = 0; i< 8; i++){
// for(int j = 0; j<7; j++){
// System.out.print(map[i][j] + " ");
// }
// System.out.println();
// }
System.out.println("===========开始走迷宫===========");
Way way = new Way();
way.getOutLet(map, 1, 1);
System.out.println("============迷宫map图=========");
for(int i = 0; i< 8; i++){
for(int j = 0; j<7; j++){
System.out.print(map[i][j] + " ");
}
System.out.println();
}
}
}
class Way{
/**
*<简述> 注意:1)需要指定规则,这个地图该如何走,这里指定 下->右->左->上 的规则;
* 2)1为墙,0为可以走,2为已经走过得地方,3为不能走
*<详细描述>
* @author Liushanshan
* @param map 地图 注意:不需要返回map,因为这里的数组是引入数据类型,用的地址是同一个
* @param i 行
* @param j 列
* @return void
*/
public boolean getOutLet(int[][] map, int i ,int j){
if(map[6][5] == 2){
return true;
}else if(map[i][j] == 0){ // 当为0时
map[i][j] = 2;
if(getOutLet(map, i+1, j)){
// 往下走可以走
return true;
}else if(getOutLet(map, i, j+1)){
// 往右走可以走
return true;
}else if(getOutLet(map,i, j-1)){
// 往左边走可以走
return true;
}else if(getOutLet(map, i-1, j)){
// 往上边走可以走
return true;
}else{
map[i][j] = 3;
return false;
}
}else {
return false;
}
}
}
package com.bear.线性结构.递归;
import com.bear.线性结构.稀疏数组.SparsearryTest;
/**
* <简述> 8皇后问题
* <详细描述>
*
* @author LiuShanshan
* @version $Id$
*/
public class Queue8 {
public static void main(String[] args) {
QueueTest queueTest = new QueueTest();
queueTest.check(0);
System.out.printf("一共有%d种解法:", QueueTest.count);
}
}
class QueueTest{
private int[] array;
private int max;
public static int count;
QueueTest(){
this.max = 8;
array = new int[max];
}
// 开始计算
public void check(int n){
// 当循环到第9行,索引为8的时候,直接放回true,并且打印出arry里面的值 (这是退出条件)
if(n == max){
print();
return;
}
// lien代表行,这里的循环代表把行里面的8个点都执行一次 todo 循环行
for(int i = 0; i<max; i++){
//先把当前这个皇后n,放到该行的第1列
array[n] = i;
// 判断是否冲突
if(judge(n)){
check(n +1);
}
}
}
// 判断是否满足8皇后的条件
private boolean judge(int n ){ //判断这一行数据跟之前的数据有没有冲突,不满足条件的
for (int i = 0; i < n; i++){ // todo 循环行,保证行里面的列与8皇后满足条件保持一致
if(array[n] == array[i] /* 判断在不在一条竖线上**/|| Math.abs(array[n] - array[i]) == Math.abs(n - i) /* 判断在不在一条斜线上**/){
return false;
}
}
return true;
}
// 打印数组里面的值
private void print(){
count++;
for (int i : array) {
System.out.print(i +" ");
}
System.out.println("\n");
}
}
非线性结构包括:二维数组,多维数组,广义表,树结构,图结构
时间复杂度是根据时间频度来的,如果时间频度是T(n) = 2n+20,则他的时间复杂度是O(n)
说明:去掉次项(去掉不重要的,留下关于n的东西),就是时间复杂度
如T(n)=n²+7n+6的时间复杂度是n²
时间复杂度的官方说明:一般情况下,算法中的基本操作语句的重复执行次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n) / f(n) 的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作 T(n)=O( f(n) ),称O( f(n) ) 为算法的渐进时间复杂度,简称时间复杂度。(说人话就是:时间频度去掉常数,去掉低次项,去掉系数,就是时间复杂度,表示为O( f(n) ) )
注释:1-8是推荐指数从高到底,最推荐的是1),最不推荐的是8)
https://www.w3cschool.cn/article/49755893.html
package com.bear.排序算法.冒泡排序;
import sun.plugin2.os.windows.FLASHWINFO;
/** 冒泡排序
* <简述>
* <详细描述>
*
* @author LiuShanshan
* @version $Id$
*/
public class BubblingDemo {
public static void main(String[] args) {
int[] arrayInt = {-1, 0 ,34, 23, 90, -5};
// 问题:将数组从小到大排序
int temp;
boolean flag = true;
// todo:解决思路:每次循环将最大/最小的数据找到,然后下一次循环-1次数
for(int i = 0; i< arrayInt.length -1; i++){ // todo 循环次数
for(int j = 0; j< arrayInt.length-1 - i; j++){ // todo 实际工作的循环次数
if(arrayInt[j] > arrayInt[j+1]){
flag = false;
temp = arrayInt[j];
arrayInt[j] = arrayInt[j+1];
arrayInt[j+1] = temp;
}
}
if(flag){
break;
}
}
for (int i : arrayInt) {
System.out.println(i);
}
}
}
假设一个长度为4的数组,循环遍历 4次,设置每一次循环的索引为n,当n =0 时,根据循环排序的规则,需要遍历后面的n=1,2,3数据相比较,如果比n=0小,则调换2者位置;当n=1时,遍历后面的n=2,3数据相比较,如果比n=1小,则交换2者位置…,一直到循环排序完,实际上循环了n-1次,因为最后一次不用循环。
package com.bear.排序算法.选择排序;
import com.bear.线性结构.稀疏数组.SparsearryTest;
/**
* <简述> 选择排序
* <详细描述>
*
* @author LiuShanshan
* @version $Id$
*/
public class SelectSort {
public static void main(String[] args) {
int[] ints = {12, 1, -1, 34, -89};
sort(ints);
}
// 选择排序
public static void sort(int[] array){
// 这里的for代表循环次数
for(int i = 0; i< array.length -1 ; i++){
int minIndex = i;
int min = array[i];
for(int j = 1 + i; j<array.length; j++){
// 查询到满足条件的数据
if(array[j] < min){
minIndex = j;
min = array[j];
}
}
// 如果发生变化,则将位置互换
if(minIndex != i){
array[minIndex] = array[i];
array[i] = min;
}
}
// 打印数据
for (int i : array) {
System.out.print(i + " ");
}
}
}
80000条数据,使用选择排序只需要4s,冒泡排序则需要很长时。
int insertVal = 0;
int insertIndex = 0;
for(int i = 1; i < arr.length; i++) {
insertVal = arr[i]; // 从第二个值开始循环往后,第一个值获取不到
insertIndex = i - 1; // 从第一个索引循环玩往后,最后一个索引获取不到;索引在值的前面,默认是在值的前面第一位
while (insertIndex >= 0 && insertVal < arr[insertIndex]) {
arr[insertIndex + 1] = arr[insertIndex];// arr[insertIndex]
insertIndex--;
}
if(insertIndex + 1 != i) {
arr[insertIndex + 1] = insertVal;
}
}
for (Integer integer : arr) {
System.out.println(integer);
}
public static void main(String[] args) {
// 需要 左索引,右索引,需要查找的值
int[] arr = {1,45,50,60,99,120};
int test = test(arr, 0, arr.length - 1, 99);
System.out.println("当前值的索引为:" + test);
}
public static int test(int[] arr, int leftIndex, int rightIndex, int valueof){
if(leftIndex > rightIndex){
return -1;
}
int midIndex = (leftIndex + rightIndex)/2;
if(arr[midIndex] < valueof){
// 往右找
return test(arr, midIndex, rightIndex, valueof);
}else if(arr[midIndex] > valueof){
// 往左找
return test(arr, leftIndex, midIndex, valueof);
}else {
return midIndex;
}
}
package com.bear.查找算法.二分查找法;
import java.util.ArrayList;
import java.util.List;
/** 二分查找法
* 二分查找法的前提就是列表需要先排好序
* @author LiuShanshan
* @version V1.0
* @Description
*/
public class BinaryTest {
public static void main(String[] args) {
// 需要 左索引,右索引,需要查找的值
int[] arr = {1,45,50,60,99,99,120};
List<Integer> objects = new ArrayList<>();
test(arr, 0, arr.length - 1, 99, objects);
System.out.println("当前值的索引为:" + objects);
}
public static void test(int[] arr, int leftIndex, int rightIndex, int valueof, List<Integer> valudofIndexArr){
if(leftIndex > rightIndex){
return ;
}
int midIndex = (leftIndex + rightIndex)/2;
if(arr[midIndex] < valueof){
// 往右找
test(arr, midIndex, rightIndex, valueof, valudofIndexArr);
}else if(arr[midIndex] > valueof){
// 往左找
test(arr, leftIndex, midIndex, valueof, valudofIndexArr);
}else {
valudofIndexArr.add(midIndex);
// 往左移动
int temp = midIndex -1;
while (true){
if(temp <0 || arr[temp] != arr[midIndex]){
break;
}
valudofIndexArr.add(temp);
temp = temp -1;
}
// 往右移动
int temp2 = midIndex + 1;
while (true){
if(temp2 > arr.length -1 || arr[temp2] != arr[midIndex]){
break;
}
valudofIndexArr.add(temp2);
temp2 = temp2 + 1;
}
}
}
}
package com.bear.查找算法.插入查找法;
import com.sun.org.glassfish.gmbal.Description;
import java.util.ArrayList;
import java.util.List;
/** 插值查找算法和二分查找法的区别在于 :midIndex 的算法不同
* @author LiuShanshan
* @version V1.0
* @Description
*/
public class CharRuBinaryTest {
public static void main(String[] args) {
// 需要 左索引,右索引,需要查找的值
int[] arr = {1,45,50,60,99,99,120};
List<Integer> objects = new ArrayList<>();
test(arr, 0, arr.length - 1, 99, objects);
System.out.println("当前值的索引为:" + objects);
}
public static void test(int[] arr, int leftIndex, int rightIndex, int valueof, List<Integer> valudofIndexArr){
if(leftIndex > rightIndex){
return ;
}
int midIndex = leftIndex + (rightIndex - leftIndex) * (valueof - arr[leftIndex]) / (arr[rightIndex] - arr[leftIndex]);
if(arr[midIndex] < valueof){
// 往右找
test(arr, midIndex, rightIndex, valueof, valudofIndexArr);
}else if(arr[midIndex] > valueof){
// 往左找
test(arr, leftIndex, midIndex, valueof, valudofIndexArr);
}else {
valudofIndexArr.add(midIndex);
// 往左移动
int temp = midIndex -1;
while (true){
if(temp <0 || arr[temp] != arr[midIndex]){
break;
}
valudofIndexArr.add(temp);
temp = temp -1;
}
// 往右移动
int temp2 = midIndex + 1;
while (true){
if(temp2 > arr.length -1 || arr[temp2] != arr[midIndex]){
break;
}
valudofIndexArr.add(temp2);
temp2 = temp2 + 1;
}
}
}
}
码云代码地址:
在这里插入代码片