数据结构与算法-1

数据结构与算法-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;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值