热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

算法和数据结构数据结构篇:数组,链表,栈和队列

生活最近还是在学习flask和java,java马上也快看完了,然后就准备开始复习一下数据结构,同时也预习一下算法。都说程序数据结构算法
生活

最近还是在学习flask和java,java马上也快看完了,然后就准备开始复习一下数据结构,同时也预习一下算法。都说程序=数据结构+算法,确实,面对不同问题选择好的数据结构和算法去编程往往能达到最高的效率,经常看到那些简短却又十分完美的代码都会十分佩服,所以决定开始好好复习一下大二学的数据结构(从树那里开始就有点忘了,哈哈)然后学学算法,体会一下那些精妙的思想。
对于数据结构和算法的基本概念,还有时间复杂度,空间复杂度什么的我就不多啰嗦了,看到好多人写的博客真的讲的很好,有兴趣的可以去搜索一下啦。

数据结构部分

我想先从数据结构开始,回顾一下我学过的数据结构:线性表,栈和队列,串,数组和广义表,树、二叉树、哈夫曼树、森林,图……还是有很多知识点的。之前学的时候是用c来写的,但既然自学了这么久java,那我就试着用java写写看,所以今天呢我想从简单的数组,链表开始。
数组和链表都是物理结构,分别是顺序存储结构和链式存储结构。那在内存中呢前者就是顺序存储,后者则是随机存储。数组便于人们去查找,但是不方便插入和删除,链表就刚好相反,相对简单的插入和删除,但是查找某个节点就要遍历链表了。栈和队列也是对应的兄弟,一个先进后出,一个先进先出,他们都是可以基于物理结构实现的逻辑结构。说了这么多,对于所有的数据结构,基本的操作都是增删改查,所以我们还是用代码来实践下。

1.数组

插入:对于数组来说,增又可以分为中间插入和尾插。尾插很简单,只要有空余空间,那就把新来的元素放进去即可,所以重点聊聊中间插入。想让一个新来的元素进入数组中,我们需要知道什么?元素的值和插入的位置也就是插入数组的下标。我们得到了该怎么做呢,首先要把这个位置腾出来,那就从这个位置开始把所有元素往后挪一位,数组大小加一**(注意:判断数组是否越界)**,然后用新加元素的值赋给这个空出来的位置。

删除:删除刚好和插入相反,从这个位置开始到最后每个元素往前移一位,并且数组大小减一。
查找:利用数组下标
修改:利用数组下标直接赋值修改
所以我就写写数组的实现和增删的代码

package 数组的插入;
//数组的插入
public class Myarray {private int[] array;private int size;public Myarray(int capacity) {this.array&#61;new int[capacity];size&#61;0;}//数组的插入public void insert(int element,int index) throws Exception{if(index<0||index>size){throw new IndexOutOfBoundsException("超出数组范围");}if(size>&#61;array.length) {resize();}for(int i&#61;size-1;i>&#61;index;i--){array[i&#43;1]&#61;array[i];}array[index]&#61;element;size&#43;&#61;1;} //数组内元素的删除1:index开始从左往右元素位置依次向左挪一位public int delete(int index) throws Exception{if(index<0||index>&#61;size){throw new IndexOutOfBoundsException("超出数组范围");}int deleted_element&#61;array[index];for(int i&#61;index;i&#61;size){throw new IndexOutOfBoundsException("超出数组范围");}int deleted_element&#61;array[index];array[index]&#61;array[size-1];size-&#61;1;return deleted_element;}public void resize(){int[] arraynew &#61; new int[array.length*2];//对原数组范围扩大两倍System.arraycopy(array, 0, arraynew, 0, array.length);//从旧数组复制到新的数组中array&#61;arraynew;}public void print(){for(int i&#61;0;i

我这里对数组越界做了处理&#xff0c;如果数组发生越界&#xff0c;我就将数组的大小变为原来的两倍。运行的结果
在这里插入图片描述

2.链表

插入&#xff1a;链表的插入相对于数组来说就比较方便&#xff0c;不用大面积的更换元素&#xff0c;插入新的节点只需要得到插入位置&#xff0c;然后找到它的前一个节点&#xff0c;将前一个节点的下一节点改为新添加的节点&#xff0c;新添加节点的下一节点变为原节点的下一节点。大概就是图里这个意思&#xff0c;画图丑别介意。
在这里插入图片描述
删除&#xff1a;和插入相反&#xff0c;得到前一个节点后再获取它的下下个节点&#xff0c;并且把前一个节点的下一个节点变为它的下下个节点。

查找&#xff1a;从头节点开始遍历数组&#xff0c;没找到需要的位置就找它的下一个节点&#xff0c;直到找到尾节点。

修改&#xff1a;根据查找到的节点&#xff0c;修改它的data

package 链表;
//实现单链表
public class Mylist {private static class Node{int data;Node next;Node(int data){ this.data&#61;data;}}private Node head;private Node last;private int size;//链表插入元素public void insert(int data,int index) throws Exception{if(index<0||index>size){throw new IndexOutOfBoundsException("超出链表范围");}Node insertnode&#61;new Node(data);if(size&#61;&#61;0){//插入头部head&#61;insertnode;last&#61;insertnode;}else if(size&#61;&#61;index){//插入尾部last.next&#61;insertnode;last&#61;insertnode;}else{//插入中间Node prevnode&#61;get(index-1);Node nextnode&#61;prevnode.next;prevnode.next&#61;insertnode;insertnode.next&#61;nextnode;}size&#43;&#61;1;}//链表删除元素public Node remove(int index) throws Exception{if(index<0||index>size){throw new IndexOutOfBoundsException("超出链表范围");}Node removenode&#61;null;if(index&#61;&#61;0){//删除头节点removenode&#61;head;head&#61;head.next;}else if(index&#61;&#61;size-1){//删除尾节点Node prevnode&#61;get(index-1);removenode&#61;prevnode.next;prevnode.next&#61;null;last&#61;prevnode;}else{//删除中间节点Node prevnode &#61;get(index-1);Node nextnode&#61;prevnode.next.next;removenode&#61;prevnode.next;prevnode.next&#61;nextnode;}size-&#61;1;return removenode;}//链表查找元素public Node get(int index) throws Exception{if(index<0||index>size){throw new IndexOutOfBoundsException("超出链表范围");}Node t&#61;head;for(int i&#61;0;i

运行结果&#xff1a;
在这里插入图片描述

3.栈和队列

前面说过&#xff0c;他们的区别并不大&#xff0c;只是一个是先进后出&#xff0c;一个是先进先出&#xff0c;如果比喻的话&#xff0c;可以把栈比喻成往瓶子里装糖果&#xff0c;最先装进去的在最底下&#xff0c;最后才会出来。而队列就像是车过隧道&#xff0c;先进去的车先出山洞。这两种数据结构可以用数组实现&#xff0c;也可以用链表实现&#xff0c;只要按照它们的定义&#xff0c;按规则来存或取就行&#xff0c;并不难。我想重点聊的是循环队列。假设我们用数组来实现队列&#xff0c;几次出队操作后前面的位置全部空出来了&#xff0c;而有可能数组已经满了&#xff0c;无法再入队&#xff0c;那么这时候前面出队的位置就浪费掉了。那我们能不能想一种方法来填满这个空出来的空间呢&#xff0c;肯定可以的&#xff0c;这就需要循环队列了。

循环队列&#xff1a;几次出队操作后&#xff0c;我们可以把队尾的指针重新回到数组的首位&#xff0c;那样入队就可以利用出队留下的空余空间。那什么时候队列真的满了呢&#xff0c;其实就是队尾指针后一个就是队头指针&#xff0c;那我们判断式的代码一般就是&#xff08;队尾&#43;1&#xff09;%数组大小&#61;队头。&#xff08;为什么不直接加一&#xff1f;有可能队尾指针在最后一个&#xff0c;队头指针在第一个&#xff09;
那我们就来实现这个循环队列

package 循环队列;
//用数组实现循环队列
public class Myqueue {public Myqueue(int capacity){this.array&#61;new int[capacity];}private int[] array;private int front;//队头private int rear;//队尾//入队enqueuepublic void enqueue(int element) throws Exception{if((rear&#43;1)%array.length&#61;&#61;front)throw new Exception("队列已经满了");array[rear]&#61;element;rear&#61;(rear&#43;1)%array.length;}//出队dequeuepublic int dequeue() throws Exception{if(rear&#61;&#61;front)throw new Exception("队列已经空了");int del&#61;array[front];front&#61;(front&#43;1)%array.length;return del;}//队列的输出public void print(){System.out.println("队列中的元素为:");for(int i&#61;front;i!&#61;rear;i&#61;(i&#43;1)%array.length){System.out.printf("%d\t",array[i]);}System.out.println();}public static void main(String[] args) throws Exception {// TODO Auto-generated method stubMyqueue que&#61;new Myqueue(6);que.enqueue(3);que.enqueue(5);que.enqueue(2);que.enqueue(8);que.dequeue();que.dequeue();que.enqueue(12);que.print();}}

在这里插入图片描述

总结

数据结构和算法其实并没有想象的那么可怕&#xff0c;只要你愿意动脑筋去多想想&#xff0c;多联系一下实际生活来体会&#xff0c;不懂的时候多画画图来模拟。当时学数据结构的时候链表啥的也是一直没搞清楚&#xff0c;但是现在回过头再来复习&#xff0c;感觉简单了很多。所以&#xff0c;千万不要有抗拒抵制心理&#xff0c;你愿意和它交朋友&#xff0c;才能更好了解它。后期呢我也会补充算法和数据结构这一块的内容&#xff0c;争取用c,c&#43;&#43;,java,python全部都实现一遍。不过这段时间很忙就没时间经常更新了&#xff0c;争取每天学的都写点东西记录保存&#xff0c;最后有时间整合一下发。


推荐阅读
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 开发笔记:9.八大排序
    开发笔记:9.八大排序 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 本文提供了使用Java实现Bellman-Ford算法解决POJ 3259问题的代码示例,详细解释了如何通过该算法检测负权环来判断时间旅行的可能性。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
    Java并发编程实践目录并发编程01——ThreadLocal并发编程02——ConcurrentHashMap并发编程03——阻塞队列和生产者-消费者模式并发编程04——闭锁Co ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文介绍如何利用动态规划算法解决经典的0-1背包问题。通过具体实例和代码实现,详细解释了在给定容量的背包中选择若干物品以最大化总价值的过程。 ... [详细]
  • 本文详细探讨了Java中的24种设计模式及其应用,并介绍了七大面向对象设计原则。通过创建型、结构型和行为型模式的分类,帮助开发者更好地理解和应用这些模式,提升代码质量和可维护性。 ... [详细]
  • 将Web服务部署到Tomcat
    本文介绍了如何在JDeveloper 12c中创建一个Java项目,并将其打包为Web服务,然后部署到Tomcat服务器。内容涵盖从项目创建、编写Web服务代码、配置相关XML文件到最终的本地部署和验证。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 本文详细探讨了JDBC(Java数据库连接)的内部机制,重点分析其作为服务提供者接口(SPI)框架的应用。通过类图和代码示例,展示了JDBC如何注册驱动程序、建立数据库连接以及执行SQL查询的过程。 ... [详细]
  • 本文详细探讨了HTML表单中GET和POST请求的区别,包括它们的工作原理、数据传输方式、安全性及适用场景。同时,通过实例展示了如何在Servlet中处理这两种请求。 ... [详细]
  • 深入解析for与foreach遍历集合时的性能差异
    本文将详细探讨for循环和foreach(迭代器)在遍历集合时的性能差异,并通过实际代码示例和源码分析,帮助读者理解这两种遍历方式的不同之处。文章内容丰富且专业,旨在为编程爱好者提供有价值的参考。 ... [详细]
author-avatar
Smitty
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有