数据结构与算法

数据结构与算法入门

1.稀疏数组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jt0Dj8zT-1659147662032)(C:\Users\mashiro\AppData\Roaming\Typora\typora-user-images\image-20220725220852410.png)]

2.队列(排队)

1.队列是一个有序列表,可以用数组或是链表来实现。

2.遵循先入先出的原则。即先存入队列的数据,要先取出。后存入的要后取出

3.队列的示意图[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zh8aIAgt-1659147662033)(C:\Users\mashiro\AppData\Roaming\Typora\typora-user-images\image-20220726150258306.png)]

4.数组模拟队列

1.将数据存入队列时称为“addQueue”,addQueue的处理需要有两个步骤:思路分析
1.将尾指针往后移:rear + 1,当front==rear【空】
2.若尾指针rear小于队列的最大下标maxSize - 1,则将数据存入rear所指的数组元素中,否则无法存入数据。rear == maxSize - 1【队列满】
public class as {
    public static void main(String[] args) throws IOException {
        ArrayQueue queue = new ArrayQueue(3);
        char key;
        Scanner scanner = 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 = scanner.next().charAt(0);//接收一个字符
            switch (key) {
                case 's':
                    queue.showQueue();
                    break;
                case 'a':
                    System.out.println("输出一个数");
                    int value = scanner.nextInt();
                    queue.addQueue(value);
                    break;
                case 'g': //取出数据
                    try {
                        int res = queue.getQueue();
                        System.out.printf("取出的数据是%d\n", res);
                    } catch (Exception e) {
                        // TODO: handle exception
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h': //查看队列头的数据
                    try {
                        int res = queue.headQueue();
                        System.out.printf("队列头的数据是%d\n", res);
                    } catch (Exception e) {
                        // TODO: handle exception
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e': //退出
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }
            System.out.println("程序退出");
        }
    }
    // 使用数组模拟队列-编写一个ArrayQueue类

}
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; // 指向队列头部,分析出front是指向队列头的前一个位置.
        rear = -1; // 指向队列尾,指向队列尾的数据(即就是队列最后一个数据)
    }

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

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

    // 添加数据到队列
    public void addQueue(int n) {
        // 判断队列是否满
        if (isFull()) {
            System.out.println("队列满,不能加入数据~");
            return;
        }
        rear++; // 让rear 后移
        arr[rear] = n;
    }

    // 获取队列的数据, 出队列
    public int getQueue() {
        // 判断队列是否空
        if (isEmpty()) {
            // 通过抛出异常
            throw new RuntimeException("队列空,不能取数据");
        }
        front++; // front后移
        return arr[front];

    }

    // 显示队列的所有数据
    public void showQueue() {
        // 遍历
        if (isEmpty()) {
            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 (isEmpty()) {
            throw new RuntimeException("队列空的,没有数据~~");
        }
        return arr[front + 1];
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6wb5lWgl-1659147662034)(C:\Users\mashiro\AppData\Roaming\Typora\typora-user-images\image-20220726165636320.png)]

2.栈

1.使用数组来模拟栈

2.定义一个top来表示栈,初始化为-1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LmGUxGIO-1659147662034)(C:\Users\mashiro\AppData\Roaming\Typora\typora-user-images\image-20220727093815336.png)]

基本算法(1.冒泡 + 选择 + 插入) 2 .(希尔 + 归并 + 快排) 3.(堆 + 基数 + 桶)

1.冒泡

2.选择

3.插入排序

public void insert(int arr[]){
        int temp;
        int index;
        for (int i = 1; i < arr.length; i++) {//自己写的用下表索引去
            temp = arr[i];
            index = i;
            for (int j = i; j >= 0; j--) {
                if (arr[j] > temp){//****
                    arr[index] = arr[j];
                    arr[j] = temp;
                    index = j;
                }
            }
            }
        }

4.希尔排序(分组 + 插入排序)

public void shellSort(int arr[]) {
        int temp;
        int index;
        int group = arr.length;
        for (int gap = group / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {//这里是核心代码,
            //因为从i = gap开始的时候就是从分组的第二个开始计算, 当前面排之后
            //前面都是从小到大排的,所以后面只需要再判定一次就可以了
                temp = arr[i];
                index = i;
                if (arr[i - gap] > temp){
                    while (index - gap >= 0 && temp < arr[index - gap]){
                    arr[index] = arr[index - gap];
                    arr[index - gap] = temp;
                    index = index - gap;
                    }
                }
            }
        }
    }

}

5.快速排序(二分 + 冒泡优化)

  int l = left; //左下标
        int r = right; //右下标
        //pivot 中轴值
        int pivot = arr[(left + right) / 2];
        int temp = 0; //临时变量,作为交换时使用
        //while循环的目的是让比pivot 值小放到左边
        //比pivot 值大放到右边
        while( l < r) {
            //在pivot的左边一直找,找到大于等于pivot值,才退出
            while( arr[l] < pivot) {
                l += 1;
            }
            //在pivot的右边一直找,找到小于等于pivot值,才退出
            while(arr[r] > pivot) {
                r -= 1;
            }
            //如果l >= r说明pivot 的左右两的值,已经按照左边全部是
            //小于等于pivot值,右边全部是大于等于pivot值


            //交换
            if (l < r) {
                temp = arr[l];
                arr[l] = arr[r];
                arr[r] = temp;
                if(arr[l] == pivot) {
                    r -= 1;
                }
                if(arr[r] == pivot) {
                    l += 1;
                }
            }
            //如果交换完后,发现这个arr[l] == pivot值 相等 r--, 前移

            //如果交换完后,发现这个arr[r] == pivot值 相等 l++, 后移

            if (l == r) {
                l += 1;
                r -= 1;
            }
        }

        // 如果 l == r, 必须l++, r--, 否则为出现栈溢出

        //向左递归
        if(left < r) {
            quickSort(arr, left, r);
        }
        //向右递归
        if(right > l) {
            quickSort(arr, l, right);
        }

两个if判断是必须要的,因为当序列中存在相同值的时候,终究会走到两个相同值相邻那一步,此时内层的两个while循环进不去,也就没办法移位,会陷入无限循环,if判断起的作用就是移位得以跳出外层while

6.归并算法(分治算法)

  public static void mergeSort(int arr[], int left, int right, int temp[]) {
        if (left < right) {
            int mid = (left + right) / 2;
            mergeSort(arr, left, mid, temp);
            mergeSort(arr, mid + 1, right, temp);
            merge(arr, left, mid, right, temp);
        }
    }

    public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
        int l = left;
        int r = mid + 1;
        int t = 0;//temp 的首下标

        while (l <= mid && r <= right) {
            if (arr[l] <= arr[r]) {
                temp[t] = arr[l];
                l++;
                t++;
            } else {
                temp[t] = arr[r];
                t++;
                r++;
            }
        }
       while (l <= mid){
           temp[t] = arr[l];
           t++;
           l++;
       }
       while (r <= right){
           temp[t] = arr[r];
           t++;
           r++;
       }
       int L = left;
       t = 0;
       while (L <= right){
         arr[L] = temp[t];
         L++;
         t++;
       }//挺简单不要注释
        
    }

7.基数排序

//1. 得到数组中最大的数的位数
		int max = arr[0]; //假设第一数就是最大数
		for(int i = 1; i < arr.length; i++) {
			if (arr[i] > max) {
				max = arr[i];
			}
		}
		//得到最大数是几位数
		int maxLength = (max + "").length();
		
		
		//定义一个二维数组,表示10个桶, 每个桶就是一个一维数组
		//说明
		//1. 二维数组包含10个一维数组
		//2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arr.length
		//3. 名明确,基数排序是使用空间换时间的经典算法
		int[][] bucket = new int[10][arr.length];
		
		//为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数
		//可以这里理解
		//比如:bucketElementCounts[0] , 记录的就是  bucket[0] 桶的放入数据个数
		int[] bucketElementCounts = new int[10];
		
		
		//这里我们使用循环将代码处理
		
		for(int i = 0 , n = 1; i < maxLength; i++, n *= 10) {
			//(针对每个元素的对应位进行排序处理), 第一次是个位,第二次是十位,第三次是百位..
			for(int j = 0; j < arr.length; j++) {
				//取出每个元素的对应位的值
				int digitOfElement = arr[j] / n % 10;
				//放入到对应的桶中
				bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
				bucketElementCounts[digitOfElement]++;
			}
			//按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
			int index = 0;
			//遍历每一桶,并将桶中是数据,放入到原数组
			for(int k = 0; k < bucketElementCounts.length; k++) {
				//如果桶中,有数据,我们才放入到原数组
				if(bucketElementCounts[k] != 0) {
					//循环该桶即第k个桶(即第k个一维数组), 放入
					for(int l = 0; l < bucketElementCounts[k]; l++) {
						//取出元素放入到arr
						arr[index++] = bucket[k][l];
					}
				}
				//第i+1轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!
				bucketElementCounts[k] = 0;
				
			}
		for(int k = 0; k < bucketElementCounts.length; k++) {
			//如果桶中,有数据,我们才放入到原数组
			if(bucketElementCounts[k] != 0) {
				//循环该桶即第k个桶(即第k个一维数组), 放入
				for(int l = 0; l < bucketElementCounts[k]; l++) {
					//取出元素放入到arr
					arr[index++] = bucket[k][l];
				}
			}
			//第i+1轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!
			bucketElementCounts[k] = 0;
			
		}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值