数据结构与算法-1
1、经典面试题:
两个字符串匹配,用KMP匹配。《部分匹配表》
汉诺塔游戏,分治算法。
8皇后:回溯算法
马踏棋盘:图的深度优化遍历算法+贪心算法优化
数据结构是一门研究数据方式的学科,有了编程语言也就有了数据结构,学号数据结构也就可以编写出更加漂亮更加有效率的算法。
程序=数据结构+算法
数据结构是算法的基础。想要学好算法就要把数据结构学到位。
修路问题:最小生成树+普利姆算法
最短路径:分支算法
线性结构:
顺序表(数组)+链表
常见:数组、队列、链表、栈
顺序表中的存储元素是连续的。
链表中的存储元素不一定是连续的。
非线性结构:
二位数组,多维数组、广义表、树结构、图结构
2、稀疏数组和队列
当一个数组大部分元素=0,或者是同一个值的时候,可以使用稀疏数组来保存该数组。
稀疏数组:
稀疏数组的处理方法:
1、记录数组一共有几行几列,有多少个不同的值
2、把具有不同数值的元素的行列及值记录在一个小规模的数组中去,从而缩小程序的规模。
将6X7----》9X3,缩小了规模
二维数组 转 稀疏数组:
遍历原始的二维数组,得到有效数据的个数sum
根据sum就可以创建稀疏数组sparseArr int【sum+1】【3】
将二位数组存到稀疏数组。
稀疏数组 转 二位数组:
先读取稀疏数组的第一行,根据第一行的数据,创建原始的二位数组,比如上面的chessArr = int【11】【11】
在读取稀疏数组后几行的数据,并赋给原始的二维数组即可。
public class demo1 { public static void main(String[] args) { int chessArr1[][] = new int[11][11]; chessArr1[1][2] = 1; chessArr1[2][3] = 2; for (int[] row : chessArr1) { for (int data : row) { System.out.printf("%d\t", data); } System.out.println(); } //遍历,得到非零数据的个数 int sum = 0; for (int i = 0; i < 11; i++) { for (int j = 0; j < 11; j++) { if (chessArr1[i][j] != 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 (chessArr1[i][j] != 0) { count++; sparseArr[count][0] = i; sparseArr[count][1] = j; sparseArr[count][2] = chessArr1[i][j]; } } } System.out.println(); System.out.println("得到的稀疏数组"); for (int i=0;i< sparseArr.length;i++){ System.out.printf("%d\t%d\t%d\n",sparseArr[i][0],sparseArr[i][1],sparseArr[i][2]); } //将稀疏数组转化为二位数组 int chessArr2[][] = new int[sparseArr[0][0]][sparseArr[0][1]]; for (int i = 1;i<sparseArr.length;i++){ chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2]; } System.out.println("回复后的数组"); for (int[] row : chessArr2) { for (int data : row) { System.out.printf("%d\t", data); } System.out.println(); } } }
队列:
队列是一个有序列表,可以用数组或是链表来实现。
front,队列头,在第一个数据的前面一个
rear:在队列尾部,包含最后一个数据。
public class demo1 { public static void main(String[] args) { //初始化一个队列 ArrayQueue arr = new ArrayQueue(3); char key =' '; Scanner sc = 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 = sc.next().charAt(0);//接受一个字符 switch (key){ case 's': arr.showQueue(); break; case 'a': System.out.println("请输入一个数"); int value = sc.nextInt(); arr.addQueue(value); break; case 'g': try { int res = arr.getQueue(); System.out.printf("取出的整数%d\n",res); }catch (Exception e){ System.out.println(e.getMessage()); } break; case 'h': try{ int i = arr.headQueue(); System.out.printf("输出队列头的数据%d\n",i); }catch (Exception e){ System.out.println(e.getMessage()); } break; case 'e': sc.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 isEmpty() { return front == rear; } public void addQueue(int n) { if (isFull()) { System.out.println("队列已经满了,不能加入数据了"); return; } rear++; arr[rear] = n; } //获取队列的数据 public int getQueue() { if (isEmpty()) { // return -1; //通过抛出异常来处理 throw new RuntimeException(("队列空了,不能取出数据")); } front++; return arr[front]; } public void showQueue() { //遍历 if (isEmpty()) { System.out.println("队列空的,没有数据"); } for (int i = 0; i < arr.length; i++) { System.out.printf("arr[%d]=%d\n", i, arr[i]); } } public int headQueue() { //判断是否为空 if (isEmpty()) { // System.out.println("队列空"); throw new RuntimeException("队列空的"); } return arr[front + 1]; } }
环形队列
含义调整:
front:front指向队列第一个元素,也就是说arr【front】就是队列的第一个元素。front=0
rear:rear指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定。rear=0
当队列满的时候,条件(rear+1)%maxsize=front,就是满的
当队列空的条件,rear=front,就是空
队列中有效的个数:rear+maxsize-front)%maxsize;
public class demo1 { public static void main(String[] args) { //初始化一个队列 CircleArray arr = new CircleArray(3); char key = ' '; Scanner sc = 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 = sc.next().charAt(0);//接受一个字符 switch (key) { case 's': arr.showCircle(); break; case 'a': System.out.println("请输入一个数"); int value = sc.nextInt(); arr.addCircleArray(value); break; case 'g': try { int res = arr.getCircleArray(); System.out.printf("取出的整数%d\n", res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'h': try { int i = arr.headCirclearray(); System.out.printf("输出队列头的数据%d\n", i); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'e': sc.close(); loop = false; break; default: break; } } System.out.println("程序推出"); } }
class CircleArray { private int maxSize; private int front; private int rear; private int[] arr; //构造器 public CircleArray(int arrMaxSize) { maxSize = arrMaxSize; arr = new int[maxSize]; } public boolean isFull() { return (rear + 1) % maxSize == front; } public boolean isEmpty() { return rear == front; } public void addCircleArray(int n) { if (isFull()) { System.out.println("队列满了,布恩那个加入数据"); return; } arr[rear] = n; rear = (rear + 1) % maxSize; } public int getCircleArray(){ if (isEmpty()){ throw new RuntimeException("队列空了"); } int n = arr[front]; front = (front+1)%maxSize; return n; } public void showCircle(){ if (isEmpty()){ System.out.println("队列空了,没有数据"); return; } for (int i=front;i<front+size();i++){ System.out.printf("arr[%d]=%d\n", i%maxSize, arr[i%maxSize]); } } public int size(){ return (rear+maxSize-front)%maxSize; } public int headCirclearray(){ if (isEmpty()){ throw new RuntimeException("队列空了"); } return arr[front]; } }
链表:
1、链表是以节点的方式来存储的。
2、每个节点包含data域,next域。指向下一个节点。
3、链表的各个节点不一定是连续存储的。
4、链表分为带头节点的链表和没有头节点的链表。
使用带head头的单向链表实现,水浒英雄排行榜管理
1)完成对英雄任务的增删改查操作
2)第一种方法在添加英雄的时候,直接添加到链表的尾部。
3)第二种方式在添加英雄的时候,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)
第一种方式:
package duilie; public class LinkLinkedList { 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, "林冲", "豹子头"); SingleLinkedList s = new SingleLinkedList(); s.add(hero1); s.add(hero4); s.add(hero2); s.add(hero3); s.show(); } } //定义管理英雄 class SingleLinkedList { private HeroNode head = new HeroNode(0, "", ""); //添加节点到单项链表 public void add(HeroNode heroNode) { HeroNode temp = head; //遍历链表 while (true) { if (temp.next == null) { break; } temp = temp.next; } temp.next = heroNode; } //显示链表 public void show() { if (head.next == null) { System.out.println("链表空"); return; } HeroNode temp = head.next; while (true) { if (temp == null) { break; } System.out.println(temp); temp = temp.next; } } } //定义一个hero node 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 + '\''+ '}'; } // }
第二种方式:
public class LinkLinkedList { 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, "林冲", "豹子头"); SingleLinkedList s = new SingleLinkedList(); s.addByOrder(hero1); s.addByOrder(hero4); s.addByOrder(hero2); s.addByOrder(hero3); s.show(); } } //第二种方式 //定义管理英雄 class SingleLinkedList { private HeroNode head = new HeroNode(0, "", ""); //添加节点到单项链表 public void add(HeroNode heroNode) { HeroNode temp = head; //遍历链表 while (true) { if (temp.next == null) { break; } temp = temp.next; } temp.next = heroNode; } public void addByOrder(HeroNode heroNode){ HeroNode temp = head; boolean flag = false;//标志添加的编号是否存在 while(true){ if(temp.next==null){ break; } if(temp.next.no>heroNode.no){ break; }else if(temp.next.no == heroNode.no){ flag=true; break; } temp = temp.next; } if(flag){ System.out.printf("准备插入的英雄的编号已经存在%d\n",heroNode.no); }else{ heroNode.next=temp.next; temp.next = heroNode; } }
HeroNode{no=1, name='宋江', nickname='及时雨'} HeroNode{no=2, name='卢弘益', nickname='玉麒麟'} HeroNode{no=3, name='吴用', nickname='智多星'} HeroNode{no=4, name='林冲', nickname='豹子头'}
对链表进行修改名字和昵称。
//修改名字 public void updata(HeroNode heroNode) { if (head.next == null) { System.out.println("链表为空"); return; } HeroNode temp = head; boolean flag1 = false; while (true) { if (temp == null) { break; } if (temp.no == heroNode.no) { flag1 = true; break; } temp = temp.next; } if (flag1){ temp.name = heroNode.name; temp.nickname = head.nickname; }else{ System.out.println("没有找到编号"); } }
删除:
public void shanchu(int no){ if (head.next==null){ return; } HeroNode temp2 = head; boolean flag = false; while(true){ if (temp2.next.no==no){ flag=true;//找到了 break; } if (temp2==null){ break; } temp2=temp2.next; } if (flag){ temp2.next = temp2.next.next; }else { System.out.println("没有找到编号"); } }
面试题:
求单链表中的节点的个数。
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个节点 public static HeroNode finLastIndexNode(HeroNode head, int index) { if (head.next == null) { return null; } //第一次遍历得到链表的个数 int size = getLength(head); //第二次遍历,size-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; }
单链表的反转:有点难度
//反转链表 public static void revearse(HeroNode head){ HeroNode head2 = new HeroNode(0, "", ""); if(head.next==null||head.next.next==null){ return; } //定义一个辅助的指针 HeroNode temp = head.next; HeroNode next = null; while(temp!=null){ next = temp.next; // if(head2==null) { // head2.next = temp; // }else{ // temp.next = head2.next; // head2.next = temp; // } temp.next=head2.next; head2.next = temp; temp = next; } head.next = head2.next; }