数据结构小结 1
来源:互联网 发布:linux socket句柄 取值 编辑:程序博客网 时间:2024/06/14 03:27
## 对几个常见的线性数据结构做一个简单的分析和自定义的实现
1.顺序表
按照顺序存储方式存储的线性表,在计算机的一组连续的存储单元中,因此在查找的时候由于地址连续性,cpu寻址时是按照顺序往下,这样在寻找时会非常迅速,这就导致了顺序存储方式的查找非常高效。同时,由于地址连续性,在中间删除或者增加一个节点时,会影响到后面节点在物理内存中的地址都要往前或往后移动,因此当插入或删除时效率较低,而且随操作影响的节点的数量越多,效率越低。这里用Java实现一个自定义的顺序表
package baseDataStructure;import java.util.Scanner;/** * 顺序表结构 * 即按照顺序存储方式的线性表类似数组 * 每个节点的长度相同,在物理内存中连续存在,一个整的空间存放顺序表 * 便于查询,增删效率低 */public class SequentialList { static final int MAXLEN = 100; //定义顺序表的最大长度 DataList[] listData = new DataList[MAXLEN+1]; //保存顺序表的结构数组 int ListLen; //顺序表已经存的节点的数量 /** * 初始化为空表,将位置指向0,这样在写入时如果有数据会直接覆盖,而不用先将数据清空 * @param sequentialList */ void init(SequentialList sequentialList){ sequentialList.ListLen=0; } /** * 返回顺序表的节点数量 * @param sequentialList * @return */ int getListLength(SequentialList sequentialList){ return sequentialList.ListLen; } /** * 插入节点 * @param sequentialList 顺序表 * @param n 插入的位置 * @param dataList 节点对象 * @return 1表示成功,0表示失败 */ int insertSequentialList(SequentialList sequentialList,int n,DataList dataList){ int i; if (sequentialList.ListLen >= MAXLEN){ System.out.println("顺序表已满,无法插入节点"); return 0; }else if (n<1||n>sequentialList.ListLen-1){ System.out.println("位置有误:当前指定位置没有存储元素,无法插入"); return 0; } for (i = sequentialList.ListLen; i >=n ; i--) { //将插入位置后面的所有元素下标向后移动一位,空出插入位置节点 sequentialList.listData[i+1] = sequentialList.listData[i]; } sequentialList.listData[n]=dataList; sequentialList.ListLen++; return 1; } /** * 在顺序表末尾加上元素 * @param sequentialList * @param dataList * @return 1表示成功,0表示失败 */ int addSequentialList(SequentialList sequentialList,DataList dataList){ if (sequentialList.ListLen>=MAXLEN){ System.out.println("顺序表已满,无法插入节点"); return 0; } sequentialList.listData[++sequentialList.ListLen]=dataList; return 1; } /** * 删除节点位置元素 * @param sequentialList * @param n * @return 1表示成功,0表示失败 */ int delSequentialList(SequentialList sequentialList,int n){ if (n<1||n>sequentialList.ListLen+1){ System.out.println("位置错误:删除节点的位置没有存有元素,无法删除"); return 0; } for (int i = n; i<sequentialList.ListLen ; i++) { //将所有n位置后面的元素都向前挪动一位,然后删除最后一个 sequentialList.listData[i]=sequentialList.listData[i+1]; } sequentialList.ListLen--; return 1; } /** * 通过下标位置查找元素 * @param sequentialList * @param n * @return */ DataList findSequentialList(SequentialList sequentialList,int n){ if (n<1||n>sequentialList.ListLen+1){ System.out.println("位置错误:查找节点的位置没有存有元素,无法查询"); return null; }else { return sequentialList.listData[n]; } } /** * 通过关键词(节点类里定义好的key)查询节点的位置返回下标 * @param sequentialList * @param key * @return 成功返回下标位置,失败返回0 */ int findSequentialListByKey(SequentialList sequentialList,String key){ for (int i = 1; i <=sequentialList.ListLen ; i++) { //compareTo 相等返回0,小于返回-1,大于返回1 if (sequentialList.listData[i].key.compareTo(key)==0){ return i; } } return 0; } /** * 显示当前顺序表所有节点内容 * @param sequentialList */ void showAllSequentialList(SequentialList sequentialList){ for (int i = 1; i <=sequentialList.ListLen ; i++) { System.out.println("第 "+i+" 个元素节点内容是\n"+sequentialList.listData[i].toString()); } } /** * 使用实例 * @param args */ public static void main(String[] args) { SequentialList sequentialList = new SequentialList(); //定义顺序表 DataList dataList; //定义节点引用的变量类型 String key; //定义查询时的关键词 sequentialList.init(sequentialList); //初始化表 Scanner sc = new Scanner(System.in); //循环添加节点内容 do { System.out.println("请输入 关键词 姓名 年龄"); DataList tmpData = new DataList(); tmpData.key = sc.next(); tmpData.name = sc.next(); tmpData.age = sc.nextInt(); if (tmpData.age!=0){ if (sequentialList.addSequentialList(sequentialList,tmpData)==0){ break; } }else { break; } }while (true); System.out.println("显示顺序表中的节点顺序"); sequentialList.showAllSequentialList(sequentialList); System.out.println("要取出的节点号码为:"); int i = sc.nextInt(); dataList = sequentialList.findSequentialList(sequentialList,i); if (dataList!=null){ System.out.println("第"+i+"个元素内容是"+dataList.toString()); } System.out.println("输入关键词"); key = sc.next(); i = sequentialList.findSequentialListByKey(sequentialList,key); dataList = sequentialList.findSequentialList(sequentialList,i); if (dataList!=null){ System.out.println("关键词为"+key +"的元素内容是"+dataList.toString()); } }}/** * 定义节点元素内容类,可以是一个任意的实体类 * 类似数组就是一个int 下标和一个Object value的实体类 */class DataList{ String key; //节点关键词 String name; int age; @Override public String toString() { return "DataList{" + "key='" + key + '\'' + ", name='" + name + '\'' + ", age=" + age + '}'; }}
2.链表
链表结构是一种动态存储分配的结构形式,一般链表有两个部分,数据部分和地址部分。数据部分用于存储节点内的数据模型等,地址部分则保存下一个节点的地址。在定义链表时,需要定义一个头引用变量(head),这个head指向链表的第一个节点,第一个节点的地址部分指向第二个节点,直到最后一个节点的地址部分指向null 则表示链表完成。因此在物理内存中基本上都是非连续存在的,比如一个8G的内存区,第一个节点在3G的位置,第二个在7G的位置,而CPU需要挨个寻址,会导致查询的效率极低。(一般情况下不会出现,因为系统会给每个进程分配一定的空间 32位系统好像是在4G,前2G作为进程私有空间,后2G作为公用空间,同时在堆空间内,因此一般不会相距太远)但是在增删时只影响上一个节点的地址部分,而不用其他的节点内容,因此效率非常高。
package baseDataStructure;import java.util.Scanner;/** * 链表自定义 * 每个节点包括两个部分,数据部分和地址部分,地址部分指向下一个节点的地址 * 如果是双向链表,地址部分还包含指向上一个节点的地址 * 链表不同于顺序表,在物理内存中不连续 * 便于增删而不便于查找 */public class LinkList { LinkListData nodeData = new LinkListData(); LinkList nextNode; /** * 在链表末尾添加节点 * @param linkList 被添加的链表对象 * @param data 需要添加的节点对象 * @return 返回添加完成的节点 */ LinkList addLinkListAtEnd(LinkList linkList,LinkListData data){ //node 表示需要添加的末尾对象 // headTemp用于存储临时赋值变量 LinkList node,headTemp; node = new LinkList(); //申请保存节点数据的内存空间 if (node==null){ System.out.println("内存申请失败,节点为空"); return null; }else { node.nodeData = data; //将需要添加的数据对象赋值给申请的节点 node.nextNode = null; //将引用节点设置为空,表示这是末尾节点 if (linkList==null){ //如果当前链表还没有存储对象 linkList = node ; return linkList; }else { headTemp = linkList; //将当前链表赋值给headTemp while (headTemp.nextNode!=null){ //查找链表尾节点 headTemp=headTemp.nextNode; } headTemp.nextNode = node; return linkList; } } } /** * 在链表头部添加节点 * @param linkList * @param data * @return */ LinkList addLinkListAtHead(LinkList linkList,LinkListData data){ LinkList node = new LinkList(); if (node==null){ System.out.println("内存申请失败,节点为空"); return null; }else { node.nodeData = data; node.nextNode = linkList; linkList = node; return linkList; } } /** * 通过关键词查询链表 * @param linkList * @param key * @return */ LinkList findLinkListByKey(LinkList linkList,String key){ LinkList tmpLinkList = linkList; //保存头节点引用 while (tmpLinkList!=null){ if (tmpLinkList.nodeData.key.compareTo(key)==0){ return tmpLinkList; }else { tmpLinkList = tmpLinkList.nextNode; } } return null; } /** * 插入节点,找到关键节点并排其后面 * @param linkList * @param findKey 插入节点需要找到对应位置,链表查找位置的条件, * @param data * @return */ LinkList insertLinkList(LinkList linkList,String findKey,LinkListData data){ LinkList node,nodeTemp; node = new LinkList(); if (node==null){ System.out.println("内存申请失败,节点为空"); return null; }else { node.nodeData = data; nodeTemp = findLinkListByKey(linkList,findKey); if (nodeTemp!=null){ node.nextNode = nodeTemp.nextNode; nodeTemp.nextNode = node; }else { System.out.println("没有找到插入的位置"); } return linkList; } } /** * 删除节点 * @param linkList * @param findKey * @return 成功返回1 失败返回0 */ int delLinkList(LinkList linkList,String findKey){ LinkList node=linkList,nodeTemp=linkList; while (nodeTemp!=null){ /** * 具体操作如下 * 假如链表为 1——> 2 ——> 3 ——> 4 需要删除3 * node 第一轮为 1——> 2 ——> 3 ——> 4 * nodeTemp 第一轮为 2 ——> 3 ——> 4 * node 第二轮为 2 ——> 3 ——> 4 * nodeTemp 第二轮为 3 ——> 4 * 第三轮时 nodeTemp 的 头节点关键词为3 执行if 操作 * 此时 node.nextNode ==> 3 ,nodeTemp.nextNode ==> 4 * 将 node.nextNode = nodeTemp.nextNode; *那么得到的 node 的链表全结果为 1 ——> 2 ——> 3 ——> 4 * */ if (nodeTemp.nodeData.key.compareTo(findKey)==0){ node.nextNode = nodeTemp.nextNode; nodeTemp = null; //释放内存 return 1; }else { node = nodeTemp; nodeTemp=nodeTemp.nextNode; } } return 0; } /** * 得到链表长度 * @param linkList * @return */ int getLengthLinkList(LinkList linkList){ LinkList tmpLinkList = linkList; int l = 0; while (tmpLinkList!=null){ l++; tmpLinkList=tmpLinkList.nextNode; } return l; } /** * 显示所有节点内容 * @param linkList */ void showAllLinkListNodes(LinkList linkList){ int i= 0; LinkList tmpLinkList = linkList; LinkListData data; while (tmpLinkList!=null){ i++; data = tmpLinkList.nodeData; System.out.println("第 "+i+" 个节点内容为 "+data.toString()); tmpLinkList = tmpLinkList.nextNode; } } public static void main(String[] args) { LinkList linkList ; LinkList headNode = null; LinkList LINK = new LinkList(); String key; Scanner sc = new Scanner(System.in); System.out.println("输入数据,关键词,姓名,年龄"); do { LinkListData data = new LinkListData(); data.key = sc.next(); if (data.key.equals("0")){ break; }else { data.name = sc.next(); data.age = sc.nextInt(); headNode = LINK.addLinkListAtEnd(headNode,data); //向headNode中添加节点 } }while (true); //显示 LINK.showAllLinkListNodes(headNode); System.out.println("删除节点关键词"); key = sc.next(); LINK.delLinkList(headNode,key); LINK.showAllLinkListNodes(headNode); System.out.println("查询关键词"); key = sc.next(); linkList = LINK.findLinkListByKey(headNode,key); if (linkList!=null){ System.out.println(key+" 查询结果为:"+linkList.nodeData.toString()); }else { System.out.println(key+" 无此结果"); } }}class LinkListData{ String key; String name; int age; @Override public String toString() { return "LinkListData{" + "key='" + key + '\'' + ", name='" + name + '\'' + ", age=" + age + '}'; }}
3.栈
从数据的运算分类上看为栈,先进后出。从数据的逻辑结构看是一种线性结构。这里主要说的是顺序栈,即在物理内存中连续存在。链式栈是链式结构存储在内存中的。栈的先进后出机制即先入栈的必须在其他节点弹出后才能取出,在栈中,只能访问当前栈顶的元素,当弹出后才能访问下一个。一般有两个操作,入栈和出栈。
入栈即将数据保存到栈顶,出栈即修改栈顶的引用使其指向下一个元素。
这里可以想象为一个特殊的数组形式,里面存放的是节点保存的数据类型可以是一个封装好的实体类等。而这个数组在添加时按照一定顺序,下标为0的保存栈底的节点,以此类推,当有n个节点保存后,栈顶的指向为n-1。在访问时,首先只能访问第n-1个,访问后将指向改为n-2,以此类推访问至最后一个节点。
package baseDataStructure;import java.util.Scanner;/** * 自定义顺序栈的实现 * 栈是一个先入后出的线性表 * 一般拥有入栈(push) 出栈(pop)两个操作 */public class SequenceStack { static final int MAXLEN = 50; SequenceStackData[] data = new SequenceStackData[MAXLEN+1]; int top; /** * 栈的初始化 * @return */ SequenceStack init(){ SequenceStack stack = new SequenceStack(); if (stack!=null){ stack.top = 0; //申请成功后申请栈顶为0 return stack; } return null; } /** * 判断是否为空栈,当栈顶top引用为0时,栈为空 * @param stack * @return 为空返回true */ boolean stackIsEmpty(SequenceStack stack){ return stack.top==0; } /** * 判断栈是否已经满了,当栈顶top达到最大值时,栈满 * @param stack * @return 满了返回true */ boolean stackIsFull(SequenceStack stack){ if (stack.top==MAXLEN){ return true; }else { return false; } } /** * 设置栈为空,将top引用置为0 * @param stack */ void stackClear(SequenceStack stack){ stack.top = 0; } /** * 释放栈空间 * @param stack */ void stackFree(SequenceStack stack){ if (stack!=null){ stack = null; } } /** * 入栈操作 * @param stack * @param data * @return */ int stackPush(SequenceStack stack,SequenceStackData data){ if (stack.top>=MAXLEN){ System.out.println("栈已满,无法入栈"); return 0; }else { stack.data[++stack.top]=data; //元素入栈 return 1; } } /** * 出栈操作 * @param stack * @return */ SequenceStackData stackPop(SequenceStack stack){ if (stack.top==0){ System.out.println("栈内没有元素内容"); return null; }else { return stack.data[stack.top--]; } } /** * 读取节点数据 * @param stack * @return */ SequenceStackData getStackData(SequenceStack stack){ if (stack.top==0){ System.out.println("没有数据在栈内"); System.exit(0); } return stack.data[stack.top]; } /** * 测试实例 * @param args */ public static void main(String[] args) { SequenceStack stack = new SequenceStack(); SequenceStackData data = new SequenceStackData(); stack = stack.init(); //初始化 Scanner sc = new Scanner(System.in); System.out.println("入栈,输入姓名,年龄"); do { SequenceStackData tmpData = new SequenceStackData(); tmpData.name = sc.next(); if (tmpData.name.equals("0")){ break; }else { tmpData.age = sc.nextInt(); stack.stackPush(stack,tmpData); } }while (true); String temp = "1"; System.out.println("出栈:任意非0键进行出栈操作"); temp = sc.next(); while (!temp.equals("0")){ data = stack.stackPop(stack); System.out.println(data.toString()); temp = sc.next(); } System.out.println("释放空间"); stack.stackFree(stack); }}/** * 简单定义栈内节点数据封装类 */class SequenceStackData{ String name; int age; @Override public String toString() { return "SequenceStackData{" + "name='" + name + '\'' + ", age='" + age + '\'' + '}'; }}
4.队列
队列从数据的逻辑结构上讲也是一种线性结构,这里也主要讲顺序队列结构,还有一种链式队列结构。队列是先进先出的规则。一般有两种操作。入队操作,将节点添加到队尾。出队操作:从队头取出节点并删除,使下一个节点成为队头。
package baseDataStructure;import java.util.Scanner;/** * 自定义顺序队列结构 * 先进先出 * */public class SequentialQueue { static final int QUEUELEN = 15; QueueData[] data = new QueueData[QUEUELEN]; int head; int tail; //定义队头和队尾 SequentialQueue queueInit(){ SequentialQueue queue; //申请内存 if ((queue=new SequentialQueue())!=null){ queue.head = 0; //设置队头为0 queue.tail = 0; //设置队尾为0 return queue; }else { return null; } } /** * 判断队列是否为空 * @param queue * @return 返回0为空 */ int queueIsEmpty(SequentialQueue queue){ if (queue.head==queue.tail){ return 0; }else { return 1; } } /** * 判断队列是否已满 * @param queue * @return 返回0为满 */ int queueIsFull(SequentialQueue queue){ if (queue.tail>=QUEUELEN){ return 0; }else { return 1; } } /** * 清空队列 * @param queue */ void queueSetClear(SequentialQueue queue){ queue.head = 0; queue.tail = 0; } /** * 释放内存 * @param queue */ void queueSetFull(SequentialQueue queue){ if (queue!=null){ queue = null; } } /** * 入队操作 * @param queue * @param data * @return 返回1成功 0失败 */ int queueIn(SequentialQueue queue,QueueData data){ if (queue.tail==QUEUELEN){ System.out.println("队列已满"); return(0); }else { queue.data[queue.tail++]=data; return(1); } } /** * 出队操作 * @param queue * @return */ QueueData queueOut(SequentialQueue queue){ if (queue.head==queue.tail){ System.out.println("出对操作:队列已空"); System.exit(0); }else { return queue.data[queue.head++]; } return null; } /** * 读取队列数据操作 * @param queue * @return */ QueueData queueGet(SequentialQueue queue){ if (queueIsEmpty(queue)==0){ System.out.println("队列已空"); return null; }else { return queue.data[queue.head]; } } /** * 计算队列长度 * @param queue * @return */ int queueLen(SequentialQueue queue){ return (queue.tail-queue.head); } /** * 测试实例 * @param args */ public static void main(String[] args) { SequentialQueue queue = new SequentialQueue(); QueueData data; Scanner sc = new Scanner(System.in); queue = queue.queueInit(); System.out.println("进行入队操作:输入姓名,年龄"); do { QueueData queueData = new QueueData(); queueData.name = sc.next(); queueData.age = sc.nextInt(); if (queueData.name.equals("0")){ break; }else { queue.queueIn(queue,queueData); } }while (true); String temp = "1"; System.out.println("出队列操作,输入任何非0键位"); temp = sc.next(); while (!temp.equals("0")){ data = queue.queueOut(queue); System.out.println("队列内容为 "+data.toString()); temp = sc.next(); } System.out.println("释放内存"); queue.queueSetFull(queue); }}/** * 简单队列节点对象数据封装 */class QueueData{ String name; int age; @Override public String toString() { return "QueueData{" + "name='" + name + '\'' + ", age=" + age + '}'; }}
- 大话数据结构小结1
- 数据结构小结 1
- 数据结构小结
- 数据结构小结
- 数据结构小结
- 数据结构小结
- 数据结构小结
- 数据结构小结
- 数据结构小结
- 数据结构与算法小结(1)
- 数据结构mooc课小结(1)
- 数据结构(期末小结)——1、数据结构概论
- Python 数据结构小结
- 数据结构第一周小结
- 数据结构第一章小结
- [数据结构]KMP小结
- 堆数据结构小结
- 数据结构与算法小结
- lua遍历文件夹, zerobrane下载
- 日志采集框架Flume以及Flume的安装部署(一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统)
- 物联网和互联网有什么区别
- Eclipse自动生成返回值
- Springboot 之 Hibernate自动建表(Mysql)
- 数据结构小结 1
- 智能机器人技术综合实训课程说明
- TP框架简单网站统计功能的实现 PV IP UV
- 工作流调度器azkaban(以及各种工作流调度器比对)
- 为RecyclerView打造通用Adapter 让RecyclerView更加好用
- Java培训:课工场面试经验大放送
- 火狐之RESTClient插件安装-yellowcong
- freemarker生成world转PDF转SWF,加载到浏览器.解决最终浏览器加载的是xml代码的问题.
- Bootstrap