数据结构与算法
正式加入csdn的第一篇博客
1.下面正式开始介绍数据结构与算法
1. 11*11的棋盘格式存储 使用稀疏数组
对于标准的棋盘一般是用二维数据存储,黑色方代表1,蓝色方代表2 下面使用
下面是一般棋盘的格式的定义及输出
public static void main(String []args) {
//定义二维数组
int arr[][] =new int[11][11];
arr[1][2]=1;
arr[2][4]=2;
//输出二维数组
for(int x=0;x<arr.length;x++){
for(int y=0;y<arr[x].length;y++){
System.out.print(arr[x][y]);
}
System.out.println();
}
}
输出:
00000000000
00100000000
00002000000
00000000000
00000000000
00000000000
00000000000
00000000000
00000000000
00000000000
00000000000
下面是稀疏数据结构对棋盘的格式的定义及输出;
public static void main(String []args) {
//定义二维数组
int arr[][] =new int[11][11];
arr[1][2]=1;
arr[2][4]=2;
//输出二维数组
for(int x=0;x<arr.length;x++){
for(int y=0;y<arr[x].length;y++){
System.out.print(arr[x][y]);
}
System.out.println();
}
//稀疏数据 需要 计算有几个不为0的数字
//第一行 行列 几个部位0的数
int sum=0;
for(int x=0;x<11;x++){
for(int y=0;y<11;y++){
if(arr[x][y] !=0){
sum++;
}
}
}
System.out.println(sum);
int sparseArr[][]=new int [sum+1][3];
sparseArr[0][0]=11;
sparseArr[0][1]=11;
sparseArr[0][2]=sum;
int count=0;
for(int i=0;i<11;i++){
for(int j=0;j<11;j++){
if(arr[i][j] != 0){
count++;
sparseArr[count][0]=i;
sparseArr[count][1]=j;
sparseArr[count][2]=arr[i][j];
}
}
}
for(int x=0;x<sparseArr.length;x++){
for(int y=0;y<sparseArr.length;y++){
System.out.print(sparseArr[x][y]);
}
System.out.println();
}
}
输出结果为:
00000000000
00100000000
00002000000
00000000000
00000000000
00000000000
00000000000
00000000000
00000000000
00000000000
00000000000
2
11112
121
242
2.使用数据实现队列的功能
下面是使用列表实现简单队列的功能
public static void main(String[] args) {
ArrayQueue queue = new ArrayQueue(3);
char key = ' ';
Scanner sacanner = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.println("s(shouw):显示队列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加数据到队尾");
System.out.println("g(get):从队列取出数据");
System.out.println("h(head):查看头部队列");
key = sacanner.next().charAt(0);
switch (key) {
case 's':
queue.showQueue();
break;
case 'a':
System.out.println("输入一个数字");
int value = sacanner.nextInt();
queue.addQueue(value);
break;
case 'g':
try {
int res = queue.getQueue();
System.out.printf("取出数据是%d\n", res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int res = queue.headQueue();
System.out.printf("队列头的数据是%d\n", res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e': //退出
sacanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出");
}
// 使用数组模拟队列
class ArrayQueue{
private int maxSize;//最大容量
private int front; //队列头
private int rear;//队列尾
private int[] arr; //存放队列
//创建构造器
public ArrayQueue(int arrMaxsize){
maxSize=arrMaxsize;
arr=new int[maxSize];
front=-1;//指向队列头部 前面一个
rear=-1;//指向队列尾部
}
//判断队列是否满
public Boolean isFull(){
return rear==maxSize-1;
}
//判断队列是否为空
public Boolean isEmty(){
return rear == front;
}
//添加数据至队列尾部
public void addQueue(int n) {
//判断队列是否已经满
if (isFull()) {
System.out.println("队列已满");
return;
}
rear++;
arr[rear] = n;
}
//获取队列的数据
public int getQueue(){
//判断队列不是否为空
if(isEmty()){
throw new RuntimeException("队列为空!添加数据");
}
front++;//front 后移
return arr[front];
}
//显示所有队列
public void showQueue(){
if(isEmty()){
System.out.println("队列为空,没有数据~~");
return;
}
for (int i=0;i<arr.length;i++){
System.out.printf("arr[%d]=%d\n",i,arr[i]);
}
}
//显示队列头部数据
public int headQueue(){
if(isEmty()){
throw new RuntimeException("队列为空!添加数据");
}
return arr[front+1];
}
}
数组实现队列缺点:
数据实现简单队列,会存在一个问题 不会形成一个环形队列 maxSize满了 队列就满了。 下一篇将手写一个环形队列
3.使用数组实现环形队列的功能
下面是创建一个环形队列 并且对环形队列的CURD
class CircleArray{
private int maxSize;//最大容量
private int front; //队列头
private int rear;//队列尾
private int[] arr; //存放队列
//创建构造器
public CircleArray(int arrMaxsize){
maxSize=arrMaxsize;
arr=new int[maxSize];
front=0;//指向队列头部 前面一个
rear=0;//指向队列尾部
}
//判断队列是否满
public Boolean isFull(){
return (rear+1)%maxSize==front;
}
//判断队列是否为空
public Boolean isEmty(){
return rear == front;
}
//添加数据至队列尾部
public void addQueue(int n) {
//判断队列是否已经满
if (isFull()) {
System.out.println("队列已满");
return;
}
//直接将数据加入
arr[rear] = n;
//需要考虑rear取模
rear = (rear + 1) % maxSize;
}
//获取队列的数据
public int getQueue() {
//判断队列不是否为空
if (isEmty()) {
throw new RuntimeException("队列为空!添加数据");
}
//这里需要分析出 front是指向队列的第一个元素
//1,先把front对应的值保存到一个临时变量
//2,将front 后移 考虑取模
//3,将临时保存的变量返回
int value=arr[front];
front=(front+1)%maxSize;
return value;
}
//显示队列头部数据
public int headQueue(){
if(isEmty()){
throw new RuntimeException("队列为空!添加数据");
}
return arr[front];
}
//显示队列头部数据
public void showQueue() {
if (isEmty()) {
System.out.println("队列为空!添加数据");
return;
}
//从front开始遍历 遍历多少个元素
for (int i = front; i < front + getSize(); i++) {
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
}
}
//当前队列的有效数据的个数
public int getSize() {
return (rear + maxSize - front) % maxSize;
}
}
测试方法:
public static void main(String[] args) {
CircleArray queue = new CircleArray(4);
char key = ' ';
Scanner sacanner = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.println("s(shouw):显示队列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加数据到队尾");
System.out.println("g(get):从队列取出数据");
System.out.println("h(head):查看头部队列");
key = sacanner.next().charAt(0);
switch (key) {
case 's':
queue.showQueue();
break;
case 'a':
System.out.println("输入一个数字");
int value = sacanner.nextInt();
queue.addQueue(value);
break;
case 'g':
try {
int res = queue.getQueue();
System.out.printf("取出数据是%d\n", res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int res = queue.headQueue();
System.out.printf("队列头的数据是%d\n", res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e': //退出
sacanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出");
}
环形队列优点
自定义队列的长度,满了会给提示,能是队列首位相连
4.单向链表分析和实现
结构图: 主要点 头节点 指向下一个节点
下面来简单实现单项链表的CURD
//定义数据结构
class HeroNode {
public int no;
public String name;
public String nickName;
public HeroNode next;
public HeroNode(int no, String name, String nickName) {
this.no = no;
this.name = name;
this.nickName = nickName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
代码实现
//定义SingleLinkedList
class SingleLinkedList {
//先初始化一个头节点,头节点不能动,不存放具体数据
private HeroNode head = new HeroNode(0, "", "");
//添加节点到单向列表
//思路 不考虑编号顺序时
//1,找到当前链表的最后节点
//2,将最后这个节点的next 指向新的节点
public void add(HeroNode headNode) {
//因为头节点不能动,因此我需要一个辅助变量
HeroNode temp = head;
//变量链表
while (true) {
//找到为空的就添加
if (temp.next == null) {
break;
}
//如果没有找到最后 就将temp后移
temp = temp.next;
}
temp.next = headNode;
}
//根据编号来修改 编码不能改
public void update(HeroNode headNode) {
//因为头节点不能动,因此我需要一个辅助变量
HeroNode temp = head;
boolean flag=false;
//变量链表
while (true) {
//找到为空的就添加
if (temp == null) {
break;
}
if(temp.no == headNode.no){
flag=true;
break;
}
//如果没有找到最后 就将temp后移
temp = temp.next;
}
if(flag){
temp.name=headNode.name;
temp.nickName=headNode.nickName;
}else{
System.out.println("没有好到编号"+headNode);
}
}
public void delete(int no){
HeroNode temp = head.next;
boolean flag=false;
while (true){
if(temp == null){
System.out.println("链表为空");
break;
}
if(temp.next.no==no){
flag=true;
break;
}
temp=temp.next;
}
if(flag){
temp.next=temp.next.next;
}else{
System.out.println("为找到需要删除的节点信息"+no);
}
}
//显示链表
public void list() {
if (head.next == null) {
System.out.println("链表为空");
return;
}
HeroNode temp = head.next;
while (true) {
//为空 说明到了最后一个
if (temp == null) {
break;
}
System.out.println(temp);
//将next后移
temp = temp.next;
}
}
public HeroNode getHeroNode(int no){
HeroNode resultNode=null;
HeroNode temp = head.next;
while (true) {
//为空 说明到了最后一个
if (temp == null) {
break;
}
if(temp.no == no ){
resultNode=temp;
break;
}
//System.out.println(temp);
//将next后移
temp = temp.next;
}
return resultNode;
}
}
测试方法
public static void main(String[] args) {
HeroNode hero1= new HeroNode(1,"宋江","及时雨");
HeroNode hero2= new HeroNode(2,"卢俊义","玉麒麟");
HeroNode hero3= new HeroNode(3,"吴用","智多星");
HeroNode hero4= new HeroNode(4,"林聪","豹子头");
HeroNode hero5= new HeroNode(5,"林聪111","豹子头111");
SingleLinkedList singleLinkedList=new SingleLinkedList();
singleLinkedList.add(hero1);
singleLinkedList.add(hero2);
singleLinkedList.add(hero3);
singleLinkedList.add(hero4);
singleLinkedList.list();
HeroNode hero6= new HeroNode(4,"林聪666666","豹子头6666");
singleLinkedList.update(hero6);
//根据编号获取数据
HeroNode resultNode= singleLinkedList.getHeroNode(4);
System.out.println("==============");
System.out.println(resultNode);
}
5.单向链表的有序插入
//第二种方式 添加数据时,需要根据排名插入到指定位置
//(如果有这个排名,则添加失败,并给出t提示)
public void addByOrder(HeroNode headNode) {
//因为头节点不能动,因此还是通过变量指针来帮忙找到添加的位置
//因为但链表,我们找的temp 是位于添加位置的前一个节点,否则插入不了
HeroNode temp = head;
boolean flag = false;//标志添加的编号是否存在
while (true) {
//说明链表在最后的位置
if (temp.next == null) {
break;
}
//位置找到了
if (temp.next.no > headNode.no) {
break;
} else if (temp.next.no == headNode.no) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
//不能添加说明编号已经存在
System.out.println("准备插入的英雄编码已经存在" + headNode);
} else {
//加入链表中 temp后面
headNode.next = temp.next;
temp.next = headNode;
}
}
4.几道简单的面试 单链表
//获取单链表的节点个数(如果带头节点的 需要吧头节点去掉)
//不需要统计头节点
public static int getLength(HeroNode head){
if(head.next == null){
return 0;
}
int length=0;
HeroNode cur=head.next;
while ( cur != null){
length++;
cur=cur.next;
}
return length;
}
//查询单链表中倒数第k个节点
//思路
//接手head节点 同时接收index
//index表示倒数第index个节点
//先把链表从头到尾遍历 得到链表的总的长度
//得到size后从链表的第一个开始遍历。遍历size-index
//找到了返回该节点 ,找不到返回空
public static HeroNode findLastIndexNode(HeroNode head,int index) {
if (head.next == null) {
return null;//没有找到
}
//第一次得到节点个数
int size = getLength(head);
//遍历size-index 就是 k个节点
//先做index校验
if (index <= 0 || index > size) {
return null;
}
HeroNode cur = head.next;
for (int i = 0; i < size - index; i++) {
cur = cur.next;
}
return cur;
}
//腾讯面试 单链表的反转
//思路
//先定义一个几点 reverseHead=new HeroNode();
//从头节点遍历原来的链表,没遍历一次节点,就将其取出,并放在链表的最前端
//原来的链表 指向新的链表
public static void reverseList(HeroNode head){
if(head.next == null || head.next.next == null ){
return ;
}
HeroNode cur=head.next;
HeroNode next=null;
HeroNode reverseHead=new HeroNode(0,"","");
while (cur != null){
next=cur.next; //先暂时保存当前节点的下一个节点,因为后面需要用到
cur.next=reverseHead.next;//将cur的下一个节点指向新的链表的的最前端
reverseHead.next=cur;//将cur连接到新的链表上
cur=next;//让cur后移
}
//让原来的head 指向最新的head
head.next=reverseHead.next;
}
//百度面试提 从尾到头打印链表
//1.先将单链表 反转 在打印 会破坏原来的单链表的结构 不建议
//2.利用栈的 数据结构,先进后出的数据结构 就实现了逆序打印的效果
public static void reversePrint(HeroNode head){
if(head.next == null){
return ;
}
Stack<HeroNode> stack=new Stack<>();
HeroNode cur=head.next;
while (cur != null){
stack.push(cur);
cur=cur.next;
}
while (stack.size()>0){
System.out.println(stack.pop());
}
}