数据结构与算法(一)

线性结构与非线性结构

线性结构

1.概述
元素数据之间存在一对一线性关系,分为两种不同的存储结构,顺序存储结构和链式存储结构
顺序存储的线性表称为顺序表,顺序表中的元素在地址上是连续的。链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息
2.常见的线性结构:数组,队列,链表,栈

非线性结构

1.常见非线性结构:二维数组,多维数组,广义表,树结构,图结构

-----------------------------------------------------并不好看分割线----------------------------------------------------------

稀疏数组
1.使用场景:当一个数组中大部分元素为0或者为相同的值,可以使用稀疏数组来保存该数组
2.处理方式:首先记录数组有几行几列,有多少个不同的值,然后,把具有不同值的行与列记录在一个小规模数组中,达到缩小数组的目的
在这里插入图片描述
3.分析:
二维数组–>稀疏数组
a.遍历原有二维数组找到有效数据的个数记录为sum
b.根据sum可以创建稀疏数组sparseArr int[sum+1][3]
c.将二维数组中的有效数据存储进入稀疏数组
稀疏数组–>二维数组
a.读取稀疏数组第一行,根据第一行创建二维数组
b.将稀疏数组中的数据填入二维数组中
4.代码实现

package sparsearray;

import java.lang.reflect.Array;

public class SparseArray {
    public static void main(String[] args) {
        //二维数组变成稀疏数组
        //创建一个二维数组
        int array[][] = new int[11][11];
        array[1][2] = 1;
        array[2][3] = 2;
        array[3][4] = 2;
        //遍历看看二维数组的样子
        for(int arr1[] : array){
            for(int data : arr1){
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }

        //获取二维数组的行和列
        int hang = array.length;
        int lie = array[0].length;
        //获取该二维数组不是0的个数
        int sum = 0;
        for(int i=0;i<hang;i++){
            for(int j=0;j<lie;j++){
                if(array[i][j]!=0){
                    sum++;
                }
            }
        }

        //创建稀疏数组
        int sparseArray[][] = new int[sum+1][3];
        sparseArray[0][0]=hang;
        sparseArray[0][1]=lie;
        sparseArray[0][2]=sum;

        //向稀疏数组中添加值
        int count = 0;
        for(int i=0;i<hang;i++){
            for(int j=0;j<lie;j++){
                if(array[i][j]!=0){
                    count++;
                    sparseArray[count][0] = i;
                    sparseArray[count][1] = j;
                    sparseArray[count][2] = array[i][j];
                }
            }
        }
        //遍历稀疏数组
        for(int i=0;i<sparseArray.length;i++){
            System.out.printf("%d\t%d\t%d\t\n",sparseArray[i][0],sparseArray[i][1],sparseArray[i][2]);
        }

        //稀疏数组变成二维数组
        //创建二维数组
        int array1[][] = new int[sparseArray[0][0]][sparseArray[0][1]];
        //向二维数组中添加值
        for(int i =1;i<sparseArray.length;i++){
            array1[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
        }
        //打印恢复后的二维数组
        System.out.println("恢复后的二维数组");
        for(int arr1[] : array1){
            for(int data : arr1){
                System.out.printf("%d\t",data);
            }
            System.out.println();
        }
    }
}

-----------------------------------------------------并不好看分割线----------------------------------------------------------

队列
1.概述:是一个有序列表,可以使用数组或者链表来实现,遵循先进先出原则
2.用数组模拟队列

package queue;

public class ArrayQueue {
    private int maxLength;//队列的最长长度
    private int front;//队列头
    private int rear;//队列尾
    private int[] arr;//队列本身

    //初始化队列
    public ArrayQueue(int length){
        maxLength = length;
        front = -1;//初始化参数,让队列头处于队列有数据的前一个
        rear = -1;//初始化参数,让队列尾就是队列的最后一个数据
        arr = new int[maxLength];
    }

    //判断队列是否为空
    public boolean isEmpty(){
        return front==rear;
    }

    //判断队列是否满
    public boolean isFull(){
        return rear == maxLength-1;
    }

    //给队列增加一个元素
    public void add(int num){
        if(isFull()){
            throw new RuntimeException("队列已满,不能添加");
        }
        rear++;
        arr[rear] = num;
    }

    //获取队列中的数据,并出队列
    public int getQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空,不能取数据");
        }
        front++;
        return arr[front];
    }

    //查看队列中的数据
    public void showQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空,不能取数据");
        }
        for(int i=0;i<arr.length;i++){
            System.out.printf("arr[%d]=%d\n",i,arr[i]);
        }
    }

    //获取队列中的头元素
    public int showFirst(){
        System.out.println("头元素"+arr[front+1]);
        return arr[front+1];
    }

    //获取队列中的尾元素
    public int showLast(){
        System.out.println("尾元素"+arr[rear]);
        return arr[rear];
    }
}

演示代码

package queue;

public class ArrayQueueTest {
    public static void main(String[] args) {
        ArrayQueue queue = new ArrayQueue(3);
        queue.add(10);
        queue.showFirst();
        queue.showLast();
        System.out.println();
        queue.add(20);
        queue.showFirst();
        queue.showLast();
        System.out.println();
        queue.getQueue();
        queue.showFirst();
        queue.showLast();
        System.out.println();
        queue.add(30);
        queue.showFirst();
        queue.showLast();
        System.out.println();
        queue.add(40);
    }
}

-----------------------------------------------------并不好看分割线----------------------------------------------------------
环形队列(数组模拟)
1.环形队列实在队列的基础上进行啦修改实现的
2.思路分析:
a.front变量:初始值为0,指向队列的第一个元素,也就是arr[front]就是队列的第一个元素
b.rear变量:初始值为0,指向队列的最后一个元素的后一个位置,比如队列有3个元素,初始front,rear都为0,当加入一个元素,front还为0,rear为1,当rear为2时,认为队列已满(因为希望空出一个空间作为约定)
c.队列满时的条件:(rear+1)% maxSize = front
d.队列为空时的条件:rear==front
e.队列中的有效的数据个数:(rear+maxSize-front)%maxSize
3.代码实现

package queue;

public class CircleArrayQueue {
    private int maxLength;//队列的最长长度
    private int front;//队列头,指向队列的第一个元素
    private int rear;//队列尾,指向队列的最后一个元素的后一个位置
    private int[] arr;//队列本身

    //初始化
    public CircleArrayQueue(int length){
        maxLength = length;
        arr = new int[maxLength];
        front = 0;
        rear = 0;
    }

    //判断队列是否为空
    public boolean isEmpty(){
        return front==rear;
    }

    //判断队列是否满
    public boolean isFull(){
        return (rear+1) % maxLength == front;
    }

    //给队列增加一个元素
    public void add(int num){
        if(isFull()){
            throw new RuntimeException("队列已满,不能添加");
        }
       arr[rear] = num;
        rear = (rear+1)%maxLength;
    }

    //获取队列中的数据,并出队列
    public int getQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空,不能取数据");
        }
        int var = arr[front];
        System.out.println(var);
        front = (front+1)%maxLength;
        return var;
    }

    //查看队列中的数据
    public void showQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空,不能取数据");
        }
        int goodLength = (rear+maxLength-front)%maxLength;
        for(int i=front;i<front+goodLength;i++){
            System.out.printf("arr[%d]=%d\n",i%maxLength,arr[i%maxLength]);
        }
    }

    //获取队列中的头元素
    public int showFirst(){
        System.out.println("头元素"+arr[front]);
        return arr[front];
    }

    //获取队列中的尾元素
    public int showLast(){
        System.out.println("尾元素"+arr[(rear+maxLength-1)%maxLength]);
        return arr[(rear+maxLength-1)%maxLength];
    }
}

package queue;

public class CircleArrayQueueTest {
    public static void main(String[] args) {
        CircleArrayQueue queue = new CircleArrayQueue(3);
        queue.add(10);
        queue.showQueue();
        System.out.println("-----------------------------------");
        queue.add(20);
        queue.showQueue();
        System.out.println("-----------------------------------");
        queue.getQueue();
        queue.showQueue();
        System.out.println("-----------------------------------");
        queue.add(30);
        queue.showQueue();
        System.out.println("-----------------------------------");
        queue.getQueue();
        queue.showQueue();
        System.out.println("-----------------------------------");
        queue.add(40);
        queue.showQueue();
        System.out.println("-----------------------------------");
    }
}

-----------------------------------------------------并不好看分割线----------------------------------------------------------
单向链表
1.概述:
a.链表是以节点的方式存储的
b.每个节点包含data域,next域:指向下一个节点
c.链表的各个节点不一定是连续存储的
d.链表分为带头结点的链表和没有头节点的链表,根据实际需求来确定
2.增删改查代码实现

package linkedlist;

public class SingleLinkedListDemo {
    public static void main(String[] args) {
        /*HeroNode heroNode1 = new HeroNode(1,"1","1");
        HeroNode heroNode2 = new HeroNode(2,"2","2");
        HeroNode heroNode3 = new HeroNode(3,"3","3");
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addHeroNode(heroNode1);
        singleLinkedList.addHeroNode(heroNode2);
        singleLinkedList.addHeroNode(heroNode3);
        singleLinkedList.findHeroNode();*/

        HeroNode heroNode4 = new HeroNode(4,"4","4");
        HeroNode heroNode5 = new HeroNode(5,"5","5");
        HeroNode heroNode6 = new HeroNode(6,"6","6");
        SingleLinkedList singleLinkedListByOrder = new SingleLinkedList();
        singleLinkedListByOrder.addByOrder(heroNode5);
        singleLinkedListByOrder.addByOrder(heroNode4);
        singleLinkedListByOrder.addByOrder(heroNode6);
        singleLinkedListByOrder.update(new HeroNode(4,"44","44"));
        singleLinkedListByOrder.delete(4);
        singleLinkedListByOrder.delete(6);
        singleLinkedListByOrder.findHeroNode();
    }
}

class SingleLinkedList{
    //头节点
    private HeroNode head = new HeroNode(0,"","");

    //增加一个节点
    public void addHeroNode(HeroNode heroNode){
        HeroNode lastHeroNode = findLastHeroNode();
        lastHeroNode.next = heroNode;
    }

    //找到最后一个节点
    public HeroNode findLastHeroNode(){
        //辅助节点
        HeroNode help = head;

        while (true){
            if(help.next==null){
                break;
            }
            help = help.next;
        }
        return help;
    }

    //遍历链表
    public void findHeroNode(){
        HeroNode hn = head.next;
        if(hn==null){
            return;
        }
        while (true){
            if(hn==null){
                break;
            }
            System.out.println(hn);
            hn = hn.next;
        }
    }

    //按照no排序插入链表
    public void addByOrder(HeroNode heroNode){
        HeroNode help = head;
        while(true){
            if(help.next==null){
                break;
            }
            if(help.next.no>heroNode.no){
                break;
            }else if(help.next.no==heroNode.no){
                System.out.println("啊重复啦");
                return;
            }
            help = help.next;
        }
        heroNode.next=help.next;
        help.next = heroNode;
    }

    //修改一个节点
    public void update(HeroNode heroNode){
        HeroNode help = head;
        while(true){
            if(help.next==null){
                break;
            }
            if(heroNode.no==help.next.no){
                HeroNode acc = help.next.next;
                if(acc==null){
                    help.next=heroNode;
                }else{
                    help.next=heroNode;
                    help.next.next=acc;
                }
                break;
            }
            help = help.next;
        }
    }

    //删除一个节点
    public void delete(int no){
        HeroNode help = head;
        while(true){
            if(help.next==null){
                break;
            }
            if(help.next.no == no){
                help.next = help.next.next;
                break;
            }
            help = help.next;
        }

    }



}

class HeroNode{
    public int no;
    public String name;
    public String nikeName;
    public HeroNode next;

    public HeroNode(int no, String name, String nikeName) {
        this.no = no;
        this.name = name;
        this.nikeName = nikeName;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nikeName='" + nikeName + '\'' +
                '}';
    }
}

-----------------------------------------------------并不好看分割线----------------------------------------------------------

双向链表
1.与单向链表的区别
a.单向链表只能一个方向查找,而双向链表可以向前,向后查找
b.双向链表可以实现自我删除

package linkedlist;

public class DoubleLinkedListDemo {
    public static void main(String[] args) {
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        doubleLinkedList.addSecretary(new Secretary(1,"小冰",22,173,8));
        doubleLinkedList.addSecretary(new Secretary(2,"小文",21,167,9));
        doubleLinkedList.addSecretary(new Secretary(3,"小欣",24,169,7));
        System.out.println("修改前");
        doubleLinkedList.getSecretarys();
        doubleLinkedList.updateSecertarys(2,10);
        System.out.println("修改后");
        doubleLinkedList.getSecretarys();
        System.out.println("删除后");
        doubleLinkedList.deleteSecertarys(3);
        doubleLinkedList.getSecretarys();
    }
}

class  DoubleLinkedList{
    private Secretary head = new Secretary(0,"",0,0,0);

    public Secretary getHead() {
        return head;
    }

    //增加(添加到末尾)
    public void addSecretary(Secretary secretary){
        //找到最后一个节点得辅助节点
        Secretary temp = head;
        while(true){
            if(temp.next == null){
                break;
            }
            temp = temp.next;
        }
        temp.next = secretary;
        secretary.pre = temp;
    }
    //遍历链表
    public void  getSecretarys(){
        Secretary temp = head;
        if(temp.next == null){
            return;
        }
        while(true){
            if(temp == null){
                break;
            }
            System.out.println(temp);
            temp=temp.next;
        }
    }

    //修改
    public void updateSecertarys(int no,int score){
        //辅助节点
        Secretary secretary = head;
        if(secretary.next == null){
            return;
        }
        while(true){
            if(secretary.next.no == no){
                secretary.next.score = score;
                break;
            }
            secretary = secretary.next;
        }
    }

    //删除节点
    public void deleteSecertarys(int no){
        //辅助节点
        Secretary secretary = head;
        while(true){
            if(secretary.no == no){
                secretary.pre.next = secretary.next;
                if(secretary.next != null){
                    secretary.next.pre = secretary.pre;
                }
                break;
            }
            secretary = secretary.next;
        }
    }
}

class  Secretary{
    public int no;
    public String name;
    public int age;
    public int height;
    public int score;
    public Secretary next;
    public Secretary pre;

    public Secretary(int no, String name, int age, int height, int score) {
        this.no = no;
        this.name = name;
        this.age = age;
        this.height = height;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Secretary{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", score=" + score +
                '}';
    }
}

-----------------------------------------------------并不好看分割线----------------------------------------------------------

约瑟夫问题:假设1,2,3…n的n个人围坐一圈,约定编号为k的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的人又出列,以此类推,直到所有人都出列,由此产生一个出队编号的序列
解决约瑟夫问题使用单向环形链表

package linkedlist;

public class Josepfu {
    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addBoy(5);
        circleSingleLinkedList.showBoys();
        circleSingleLinkedList.jse(1,2);
    }
}

class CircleSingleLinkedList{
    private Boy first = null;
    //增加
    public void addBoy(int num){
        if(num<2){
            System.out.println("至少2个");
            return;
        }
        Boy preBoy = null;
        Boy thisBoy = null;
        for(int i=1;i<num+1;i++){
            Boy boy = new Boy(i);
            if(i==1){
                first = boy;
                preBoy = boy;
                preBoy.setBoy(boy);
            }else{
                thisBoy = boy;
                preBoy.setBoy(boy);
                thisBoy.setBoy(first);
                preBoy = boy;
            }
        }
    }

    //循环遍历
    public void showBoys(){
        Boy boy = first;
        while(true){
            System.out.println(boy);
            if(boy.getBoy() == first){
                break;
            }
            boy = boy.getBoy();
        }
    }

    //约瑟夫问题
    public void jse(int startNo,int number){
        //两个辅助节点,一个指向当前节点,一个指向当前节点的前一个
        Boy start = first;
        Boy helper = first;
        //这个循环是让helper是start的前一个
        while(true){
            if(helper.getBoy() == first){
                    break;
            }
            helper = helper.getBoy();
        }
        //根据从那个开始,确定start和helper的位置
        for(int i=1;i<startNo;i++){
            helper = helper.getBoy();
            start = start.getBoy();
        }
        while(true){
            if(start == helper){
                break;
            }
            for(int i=1;i<number;i++){
                helper = helper.getBoy();
                start = start.getBoy();
            }
            System.out.println("出圈:"+start);
            helper.setBoy(start.getBoy());
            start = start.getBoy();
        }

    }
}

class Boy{
    private int no;
    private Boy boy;

    public Boy(int no) {
        this.no = no;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public Boy getBoy() {
        return boy;
    }

    public void setBoy(Boy boy) {
        this.boy = boy;
    }

    @Override
    public String toString() {
        return "Boy{" +
                "no=" + no +
                '}';
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值