热门标签 | 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编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 本文详细解析了Python中的os和sys模块,介绍了它们的功能、常用方法及其在实际编程中的应用。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 根据最新发布的《互联网人才趋势报告》,尽管大量IT从业者已转向Python开发,但随着人工智能和大数据领域的迅猛发展,仍存在巨大的人才缺口。本文将详细介绍如何使用Python编写一个简单的爬虫程序,并提供完整的代码示例。 ... [详细]
  • 本文提供了使用Java实现Bellman-Ford算法解决POJ 3259问题的代码示例,详细解释了如何通过该算法检测负权环来判断时间旅行的可能性。 ... [详细]
  • 本文详细介绍如何在VSCode中配置自定义代码片段,使其具备与IDEA相似的代码生成快捷键功能。通过具体的Java和HTML代码片段示例,展示配置步骤及效果。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 探讨一个显示数字的故障计算器,它支持两种操作:将当前数字乘以2或减去1。本文将详细介绍如何用最少的操作次数将初始值X转换为目标值Y。 ... [详细]
  • MQTT技术周报:硬件连接与协议解析
    本周开发笔记重点介绍了在新项目中使用MQTT协议进行硬件连接的技术细节,涵盖其特性、原理及实现步骤。 ... [详细]
  • 掌握远程执行Linux脚本和命令的技巧
    本文将详细介绍如何利用Python的Paramiko库实现远程执行Linux脚本和命令,帮助读者快速掌握这一实用技能。通过具体的示例和详尽的解释,让初学者也能轻松上手。 ... [详细]
  • 利用存储过程构建年度日历表的详细指南
    本文将介绍如何使用SQL存储过程创建一个完整的年度日历表。通过实例演示,帮助读者掌握存储过程的应用技巧,并提供详细的代码解析和执行步骤。 ... [详细]
  • 本文详细介绍了macOS系统的核心组件,包括如何管理其安全特性——系统完整性保护(SIP),并探讨了不同版本的更新亮点。对于使用macOS系统的用户来说,了解这些信息有助于更好地管理和优化系统性能。 ... [详细]
  • 最近团队在部署DLP,作为一个技术人员对于黑盒看不到的地方还是充满了好奇心。多次咨询乙方人员DLP的算法原理是什么,他们都以商业秘密为由避而不谈,不得已只能自己查资料学习,于是有了下面的浅见。身为甲方,虽然不需要开发DLP产品,但是也有必要弄明白DLP基本的原理。俗话说工欲善其事必先利其器,只有在懂这个工具的原理之后才能更加灵活地使用这个工具,即使出现意外情况也能快速排错,越接近底层,越接近真相。根据DLP的实际用途,本文将DLP检测分为2部分,泄露关键字检测和近似重复文档检测。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 作者:守望者1028链接:https:www.nowcoder.comdiscuss55353来源:牛客网面试高频题:校招过程中参考过牛客诸位大佬的面经,但是具体哪一块是参考谁的我 ... [详细]
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社区 版权所有