zoukankan      html  css  js  c++  java
  • 数据结构

    1.  几个景点算法:

         1. 修路问题:最小生成树(加权值)+ 普利姆

         2.   最短路径:图+弗洛伊德算法

         3.   汉诺塔: 分支的算法

         4.  八皇后:回朔法、

         5. 丢手帕  : 约瑟夫问题

    2. 线性结构 与非线性结构

           1.线性结构 :数据元素之间存在一对一的线性关系

                 顺序存储结构 ,  链式存储结构

                 (数组,队列,链表和栈)

           2 . 非线性结构:(二维数组,多维数组,广义表,树结构,图结构)

    3. 稀疏数组

                    

                 因为该数组中记录了很多值是默认值0,记录了很多没有意义的数据  -》 稀疏数组

                     

                    

    代码实现原始二维数组与稀疏数组之间的转化

                             

    import org.junit.Test;
    
    public class XiShuJuZhen {
        
        //创建一个原始的二维数组 11*11
        @Test
        public void testArray() {
             int[][] charArray =  new int[11][11];
             //0表示没有棋子,1 表示黑子  2表示蓝子
                charArray[1][2] = 1;
                charArray[2][3] = 2;
                charArray[4][5] = 2;
                System.out.println("输出原始的二维数组");
                for (int[] is : charArray) {
                    for (int is2 : is) {
                        System.out.print("	"+is2);
                    }
                    System.out.println();
                    
                }
                /*
                 * 将二维数组转为稀疏数组的思路
                 * (1).先遍历二维数组,得到非0整数的个数
                 */
                int sum =  0;
                for(int i=0;i<11;i++) {
                    for(int j=0;j<11;j++) {
                        if(charArray[i][j]!=0) {
                            sum++;
                        }
                    }
                }
                System.out.println("sum = "+sum);
                
                //2 .创建对应的稀疏数组
                int sparseArr[][] = new int[sum+1][3] ;
                //给稀疏数组赋值
                sparseArr[0][0] = 11; //有11行
                sparseArr[0][1] = 11;  //有11列
                sparseArr[0][2] = sum; //有多少个值
                
                int count= 0; //count 用于记录是第几个非0数据
                for(int i=0;i<11;i++) {
                    for(int j=0;j<11;j++) {
                        if(charArray[i][j]!=0) {
                            count++;
                            sparseArr[count][0] = i;  //第0 列,第count行
                            sparseArr[count][1] = j;  //第1列,第count行
                            sparseArr[count][2]  =charArray[i][j];//第2列 存入的是二维数组不为0的值
                            
                        }
                    }
                }
                System.out.println("输出稀疏数组的形式");
                for (int[] is : sparseArr) {
                    for (int is2 : is) {
                        System.out.print("	"+is2);
                    }
                    System.out.println();
                }
                //恢复成二维数组
                //先读取稀疏数组的第一行将新创建的数组进行赋值确定数组大小
                int[][] charArray1 = new int[sparseArr[0][0]][sparseArr[0][0]];
                
                //再读取稀疏数组的后几行,从第二行开始,并赋给原始的二维数组
                for(int i=1;i<sparseArr.length;i++) {
                    //为原始数组进行赋值
                    charArray1[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
                }
                System.out.println("恢复后的原始二维数组");
                for (int[] is : charArray1) {
                    for (int is2 : is) {
                        System.out.print("	"+is2);
                    }
                    System.out.println();
                }
        }    
    }
    代码实现

     使用IO流将数据保存起来 其实我没有明白是什么意思,然后我就写了一个IO流将数据以文本的方式保存起来了

                             

    public static void main(String[] args) throws IOException {
            //创建一个字节流输出流
            FileOutputStream fileOutputStream = new FileOutputStream("D:/lucenezhulina/a.txt");
            
            //将字节流转化为字符流
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
            
            //使用缓冲区进行缓冲
             BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
             
        //     bufferedWriter.write("朱李纳");
             
             //0表示没有棋子,1 表示黑子  2表示蓝子
                String str1 = "int[][] charArray =  new int[11][11];";
                String str2 = "charArray[1][2] = 1;";
                String str3 = "charArray[2][3] = 2;";
                String str4 = "charArray[4][5] = 2;";
                
            bufferedWriter.write(str1);
            
            bufferedWriter.write(str2);
            bufferedWriter.write(str3);
            bufferedWriter.write(str4);
            bufferedWriter.close();
            
             //创建 一个字节输入流
             FileInputStream fileInputStream = new  FileInputStream("D:/lucenezhulina/a.txt");
             
             //将字节流转化为字符流
             InputStreamReader inputStreamReader = new  InputStreamReader(fileInputStream);
            
             //使用缓冲流
             BufferedReader bufferedReader = new  BufferedReader(inputStreamReader);
             String readLine = bufferedReader.readLine();
             System.out.println(readLine);
             //读取数据
            /* while(true) {
                 String readLine = bufferedReader.readLine();
                 if(readLine==null) {
                     break;
                 }
                 System.out.println(readLine);
             }*/
             
             bufferedReader.close();
        }
    代码

    改进后的代码

                                

    import java.awt.event.FocusAdapter;
    import java.util.Scanner;
    
    import javax.management.RuntimeErrorException;
    
    import org.junit.Test;
    
    public class CircleQueue {
         
        private int  maxSize;//表示数组的最大容量
        private int front;//front指向队列的第一个元素
        private int rear;//队列尾
        private int arr[];//该数组用于存放数据,模拟队列
        
        
        //定义一个构造器给与数组初始大小
        public CircleQueue(int arrMaxSize) {
            maxSize = arrMaxSize;
            arr = new int[maxSize];
        }
        
        //判断队列是否满
        public boolean isFull() {
            
            return (rear+1) % maxSize == front; //rear+1 最大和maxSize相同
        }
        
        //添加数据到队列
        public void addQueue(int n) {
            //判断队列是否满
            if(isFull()) {
                System.out.println("队列已满,不能加入");
                return;
            }
            arr[rear] = n;
            rear = (rear+1)%maxSize; //rear不可能比maxSize大因此余数就是rear+1,也就是rear向后移动一个值
        }
        //判断队列是否为空
        public boolean isEmpty() {
            
            return rear==front;
        }
        //获取队列的数据出队列
        public int getQueue() {
            if (isEmpty()) {
                throw new RuntimeException("队列空,不能取数据");
            }
            int value = arr[front];
             front = (front+1)%maxSize; //front最大是与rear相同比maxSize小1
          return value;
        }
        //显示队列的所有数据
        public void showQueue() {
            //遍历
            if(isEmpty()) {
                System.out.println("队列是空的,没有数据");
                return;
            }
            for(int i=front;i<front+size();i++) {
                System.out.printf("arr[%d]=%d
    ",i%maxSize,arr[i%maxSize]);
            }
        }
        //求出当前列有效数据个数
        public int size() {
            return (rear+maxSize -front)%maxSize;
        }
        
        //显示头信息
        public int  headQueue() {
            //判断
        if(isEmpty()) {
            System.out.println("队列为空,没有投数据");
            throw new RuntimeException("队列空的没有数据");
        }
            return arr[front];
        
        }
    }
    
    public class TestCircleQueue {
        @Test
        public  void test01() {
            //创建一个队列对象
            CircleQueue arrayQueue = new CircleQueue(4);
            //接收用户输入
            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':
                    arrayQueue.showQueue();
                    break;
                case 'e': //退出程序
                    sc.close();
                    loop = false;
                    break;
                case 'h': //查看队列头的数据
                    try {
                       int res = arrayQueue.headQueue();
                       System.out.println("队列头的数据是: "+res);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    
                    break;
                case 'a':
                    System.out.println("输入一个数");
                    int value = sc.nextInt();
                    arrayQueue.addQueue(value);
                    break;
                case 'g':  //取出数据
                    try {
                        int res = arrayQueue.getQueue();
                        System.out.println("取出的数据是:"+res);
                    }catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
    
                default:
                    break;
                }
            }
            System.out.println("程序退出");
        }
    }
    具体代码实现

     使用循环链表,这种方式不能进行排序,如果插入的顺序不一样,不能自动的进行排序

                               

    class SingleLinkedListDemo {
        public static void main(String[] args) {
            //进行测试
            //先创建节点
            HeroNode heroNode1 = new HeroNode(1, "宋江" , "及时雨");
            HeroNode heroNode2 = new HeroNode(2, "卢俊义" , "玉麒麟");
            HeroNode heroNode3 = new HeroNode(3, "吴用" , "智多星");
            HeroNode heroNode4 = new HeroNode(4, "林冲" , "豹子头");
            
            //创建链表
            SingleLinkedList singleLinkedList = new SingleLinkedList();
            //加入
        /*    singleLinkedList.add(heroNode1);
            singleLinkedList.add(heroNode2);
            singleLinkedList.add(heroNode3);
            singleLinkedList.add(heroNode4);*/
            
            //加入按照编号的顺序
            singleLinkedList.addByOrder(heroNode1);
            singleLinkedList.addByOrder(heroNode4);
            singleLinkedList.addByOrder(heroNode2);
            singleLinkedList.addByOrder(heroNode3);
            //遍历
            singleLinkedList.list();
            
        }
    }
    //定义SingleLinkedList 管理我们的英雄
    class SingleLinkedList{
        //先初始化一个头节点,头节点不要动,不存放具体的数据
        private HeroNode head = new HeroNode(0,"","");
        
        //添加节点到单向链表
        /**
          * 思路:当不考虑编号顺序时
         * 1.找到当前链表的最后节点
         * 2.将最后节点的这个next指向新的节点
         */
        public void add(HeroNode heroNode) { 
            //因为head节点不能动,因此我们需要一个辅助遍历temp
            HeroNode temp = head;
            //遍历链表,找到最后
            while(true) {
                //找到链表的最后
                if (temp.next==null) {
                    break;
                }
                //如果没有找到就将temp后移
                temp=temp.next;
            }
            //当退出while循环时,temp就指向了链表的最后
            //将最后节点的这个next指向新的节点
            temp.next = heroNode;
        }
        //第二种方式在添加英雄时,根据排名将英雄添加到指定位置
        //如果有这个排名,择添加失败并给出提示
        public void addByOrder(HeroNode heroNode) {
            //应为头结点不能动,我们通过一个辅助变量帮助找到添加的位置
            HeroNode temp = head;
            boolean flag = false; //标识添加的这个编号是否存在默认是false
            while (true) {
                if(temp.next==null) {//说明temp节点已经在链表的最后
                    break;
                }
                if (temp.next.no>heroNode.no) {//位置找到,就在temp的后面插入
                    break;
                    
                }else if(temp.next.no == heroNode.no) {//说明希望添加的heroNode的编号已然存在
                    flag = true;//说明编号存在
                    break;
                }
                temp = temp.next; //后移,遍历当前的链表
            }
            
            
            //判断flag的值
            if (flag) { //不能添加,说明编号存在
                System.out.printf("准备插入的英雄的编号 %d 已经存在了,不能加入
    ",heroNode.no);
                
            }else {
                //插入到链表中,temp的后面
                heroNode.next = temp.next;
                temp.next = heroNode;
                
            }
            
        }
        //显示链表 遍历
        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);
                 //将这个temp后移
                 temp = temp.next;
            }
            
        }
    
        
    }
    //定义HeroNode ,每一个HeroNode对象就是一个节点
    class HeroNode{
        public int no;
        public String name;
        public String nickname; //昵称
        public HeroNode next; //指向下一个节点
        
        //构造器  传入三个参数一个编号,姓名,昵称
        public HeroNode(int hNo,String hName,String hNickName) {
             this.no = hNo;
             this.name = hName;
             this.nickname = hNickName;
        }
    
        @Override
        public String toString() {
            return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + ", next=" + next + "]";
        }
        
        
        
        
        
        
        
    }
    具体代码实现

     单链表的修改操作

                                    

    //修改节点的信息,根据no编号来修改,即no不能改
        public void update(HeroNode newHeroNode) {
            //判断是否为空
            if (head.next==null) {
                System.out.println("链表为空");
                return;
            }
            //找到需要修改的节点,根据no编号
            //定义一个辅助变量
            HeroNode temp = head.next;
            boolean flag = false;  //表示是否找到该节点
            while(true) {
                if(temp==null) {
                    break;//已经遍历完链表 在遍历的过程中temp一直在向后走到达最后一个next为null
                }if (temp.no == newHeroNode.no) {
                    //找到
                    flag = true;
                    break;
                }
                temp = temp.next;
            }
            //根据flag判断是否找到要修改的节点
            if(flag==true) {
                temp.name = newHeroNode.name;
                temp.nickname = newHeroNode.nickname;
            }else {
                //没有找到
                System.out.printf("没有找到编号为 %d 的节点,不能修改
    ",newHeroNode.no);
            }
        }
        
    修改后的代码
        //测试修改节点的代码
            HeroNode heroNode = new HeroNode(2, "小卢", "玉麒麟");
            singleLinkedList.update(heroNode);
            
            System.out.println("修改后");
            singleLinkedList.list();
    测试代码

                                    

     删除节点

                                         

    //删除节点
        public void delete(int no) {
            HeroNode temp = head;
            boolean flag = false; //标志是否找到待删除节点的前一个节点
            while(true) {
                if (temp.next==null) { //已经遍历到了链表尾
                    break;
                }
                if (temp.next.no ==no) {
                    //找打了待删除节点的前一个节点
                    flag = true;
                    break;
                }
                //若没有找到temp后移继续遍历
                temp  = temp.next;
            }
            //判断flag 
            if (flag ==true) {
                //找到
                temp.next = temp.next.next;
            }else {
                System.out.printf("要删除的 %d 节点不存在
    ",no);
            }
            
        }
        
    删除节点代码
    //删除一个节点
            singleLinkedList.delete(1);
            System.out.println("删除后链表结构");
            singleLinkedList.list();
    删除节点代码测试

     几个经典面试题:

    将单链表进行翻转

    //将单链表进行翻转
        public static void reverseLinked(HeroNode heroNode) {
            //如果当前链表为空,或者只有一个节点就无需翻转 直接返回
            if (heroNode.next==null|| heroNode.next.next==null) {
                return ;
            }
            //定义一个辅助的指针,帮我们遍历原来的链表
            HeroNode current =heroNode.next;
            HeroNode next = null; //指向当前节点current的下一个节点 相当一next代替current向后移动
            HeroNode reverseHead = new HeroNode(0, "", "");
            //遍历原来的链表每遍历一个节点就将其取出,并放在新的链表reverseHead的最前端
            
            while(current !=null) {
                next = current.next; //先暂时保留current的下一个节点
                current.next =  reverseHead.next; //将当前节点的下一个节点置为空 目的是使
                //    当前current 称为新链表的第一个节点
                reverseHead.next = current; //当前节点称为了新链表的第一个节点
                current   = next; //现在current指向了原来链表的下一个节点,也就是让current后移
            }
            //最后将head.next指向reverseHead.next,实现单链表的反转
            heroNode.next = reverseHead.next;
        }
        
    将单链表进行反转

    测试:

        //测试单链表的反转
            System.out.println("反转后链表的情况");
            reverseLinked(singleLinkedList.getHead());        
            singleLinkedList.list();
    测试

    查找单链表中的倒数第k个节点 新浪面试题

    //查找单链表中的倒数第k个节点 新浪面试题
        /*
         * 思路:编写一个方法,接收head节点同时接收一个index,index 表示倒数第index个节点
         * 先把链表从头到尾遍历,然后减去index就是我需要遍历的长度
         */
        
        public static HeroNode returnSignIndexNode(HeroNode heroNode,int index) {
            //如果链表尾空就返回null
            if (heroNode.next==null) {
                return null;
            }
            //第一次遍历获取链表的长度
            int size = getLength(heroNode);
            
            //第二次遍历 size-index位置就是我们倒数的第k的节点
            //先做一个index的校验
            if(index<=0||index>size) {
                return null;
            }
            //定义辅助变量,for循环定位到倒数的index
            HeroNode current = heroNode.next;
            for(int i=0;i<size-index;i++) {
                current = current.next;
            }
            return current;
        }
        
    倒数第k个节点

    测试:

    //测试是否得到了倒数第k个节点
            HeroNode res = returnSignIndexNode(singleLinkedList.getHead(), 1);
            System.out.println("倒数第1 res = "+res);
    测试

    查找单链表有效节点的个数不统计头结点

    //查找单链表有效节点的个数不统计头结点
        public static int getLength(HeroNode heroNode) {
            
            if(heroNode.next ==null) { //空链表
                
                 return 0;
            }
            int count = 0;
            HeroNode current;
            current = heroNode.next;
            while(current!=null) {
                count++;
                current = current.next;
            }
            return count;
        }
    View Code

    测试:

    //测试一下 求单链表中有效节点的个数
            System.out.println("有效的节点个数:"+getLength(singleLinkedList.getHead()));
    测试

     从尾到头打印单链表

     /*
            * 从尾到头打印单链表
         *  思路:方式一:先将单链表进行翻转操作,然后再遍历即可,这样做的问题是会破坏原来的单链表的结构
         *  不建议。
         *  方式二:可以利用栈这个数据结构,将个个节点压入栈中,然后利用栈的先进后出的特点,就实现了
         *  逆序打印的效果。
         */
        public static void  reversePrint(HeroNode heroNode) {
            if(heroNode.next==null) {
                return; //空链表,不能打印
            }
            //创建一个栈,将各个节点压入栈中
            Stack<HeroNode> stack = new Stack<HeroNode>();
            
            HeroNode current = heroNode.next;
            //将链表的所有的节点压入栈中
            while(current!=null) {
                stack.push(current);
                current = current.next; //current后移
            }
            //将栈中的节点进行打印,pop 出栈
            while(stack.size()>0) {
                System.out.println(stack.pop());//先进后出    出栈
            }
        }
        
    View Code

    测试

      System.out.println("测试逆序打印单链表,没有改变原来链表的结构");
            reversePrint(singleLinkedList.getHead());
    测试

                   

  • 相关阅读:
    Oracle与MySQL的转化差异
    iOS 创建静态库文件时去掉当中的Symbols
    hdu4336 Card Collector 状态压缩dp
    随机森林——Random Forests
    OpenCV码源笔记——Decision Tree决策树
    海明距离hamming distance
    学习OpenCV——Surf简化版
    学习OpenCV——用OpenCv画漫画
    学习OpenCV——ORB简化版&Location加速版
    学习OpenCV——hand tracking手势跟踪
  • 原文地址:https://www.cnblogs.com/zhulina-917/p/11576905.html
Copyright © 2011-2022 走看看