数据结构与算法-总结线性表顺序存储结构的优缺点

最后更新于:2022-04-01 07:04:35

这一章节主要总结线性表顺序存储结构的优缺点。 在总结之前,我们来讨论一下线性表顺序存储结构的执行方法的时间复杂度: 存储、读取:O(1) 插入、删除:O(n) 优点: 1.无需为表中的逻辑关系增加额外的存储空间 2.可以快速存取表中对象 缺点: 1.插入和删除需要移动大量的对象 2.存储设备的碎片化 3.当线性表过大的时候,很难确定长度
';

数据结构与算法-线性表顺序存储结构删除操作的实现

最后更新于:2022-04-01 07:04:33

这一章节我们来看一下线性表顺序存储结构删除操作的简单实现 ~~~ package com.ray.testobject; public class Test { private Object[] list; public Object[] getList() { return list; } /** * 初始化list * * @param num * 元素个数 */ private void iniList(int num) { list = new Object[num]; for (int i = 0; i < num; i++) { list[i] = new Object(); } } /** * 删除某个元素 * * @param pos * 元素位置 */ private Object delItemOfList(int pos) { Object delItem = null; if (pos <= 0 || pos > list.length) { System.out.println("输入位置不正确,不能执行删除方法"); return delItem; } delItem = list[pos - 1]; list[pos - 1] = null; if (pos < list.length) { for (int i = pos; i < list.length; i++) { list[i - 1] = list[i]; } list[list.length - 1] = null; } return delItem; } public static void main(String[] args) { Test test = new Test(); test.iniList(5); for (int i = 0; i < test.getList().length; i++) { System.out.println(test.getList()[i]); } System.out.println("--------------------"); System.out.println("被删除的元素:" + test.delItemOfList(3)); for (int i = 0; i < test.getList().length; i++) { System.out.println(test.getList()[i]); } } } ~~~ 输出: java.lang.Object@1fb8ee3 java.lang.Object@61de33 java.lang.Object@14318bb java.lang.Object@ca0b6 java.lang.Object@10b30a7 -------------------- 被删除的元素:java.lang.Object@14318bb java.lang.Object@1fb8ee3 java.lang.Object@61de33 java.lang.Object@ca0b6 java.lang.Object@10b30a7 null 注意:上面的代码只是一个简单的模拟,如果有问题,请指出,谢谢。
';

数据结构与算法-线性表顺序存储结构插入操作的实现

最后更新于:2022-04-01 07:04:30

今天来说说线性表的实现 这里以List作为例子 ~~~ package com.ray.testobject; public class List { private int length; private Man[] array; public int getLength() { return length; } public void setLength(int length) { this.length = length; } public Man[] getArray() { return array; } public void setArray(Man[] array) { this.array = array; } } ~~~ list只是简单的封装了一个数组和一个整形数的长度 ~~~ package com.ray.testobject; public class Test { // 构造一个不满的线性表出来 private List initList() { List list = new List(); int n = 5; list.setArray(new Man[n + 1]);// 构造多一个元素的线性表 for (int i = 0; i < n; i++) { Man man = new Man(); man.setId(i); list.getArray()[i] = man; list.setLength(i + 1); } return list; } private boolean insertElement(List list, int pos, Man e) { boolean flag = false; Man[] array = list.getArray(); if (list.getLength() == array.length) { return false; } if (pos < 1 || pos > array.length) { return false; } if (pos < array.length) { for (int i = array.length-1; i > pos-1; i--) { array[i] = array[i - 1]; } } array[pos] = e; list.setLength(list.getLength() + 1); return flag; } public static void main(String[] args) { Test test = new Test(); List list = test.initList(); Man man = new Man(); man.setId(10); test.insertElement(list, 3, man); for (int i = 0; i < list.getArray().length; i++) { System.out.println(list.getArray()[i].getId()); } } } ~~~ 在上面的测试类里面,我们实现了List的初始化与插入元素,后面还会继续实现删除等方法
';

数据结构与算法-抽象数据类型

最后更新于:2022-04-01 07:04:28

抽象数据类型概念(百度版) 抽象数据类型(Abstract Data Type 简称ADT)是指一个数学模型以及定义在此数学模型上的一组操作。 它包括数据对象、数据关系、操作集合 例子:arraylist ADT ArrayList{        数据对象:D={a1,a2,a3,....an-1,an}        数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,…,n}        基本操作:        Init():void         操作结果:构造一个空的线性表L        Destroy():boolean         初始条件:线性表已存在         操作结果:销毁线性表L        Clear():boolean         初始条件:线性表已存在         操作结果:置线性表L为空表       isListEmpty():boolean         初始条件:线性表已存在         操作结果:若线性表L为空表,则返回TRUE,否则返回FALSE       Lenght():int         初始条件:线性表已存在         操作结果:返回线性表L数据元素个数        GetElementAt(i):e         初始条件:线性表已存在(1≤i≤ListLenght(L))         操作结果:返回e代表线性表L中第i个数据元素的值        locatElem(e):int         初始条件:线性表已存在,comare()是数据元素判定函数         操作结果:返回线性表L中第1个与e相同的位序,没有返回0        PreElem(e):e         初始条件:线性表已存在         操作结果:若e是线性表L的数据元素,且不是第一个,则返回它的前驱,否则操作失败        NextElem(e):e         初始条件:线性表已存在         操作结果:若e是线性表L的数据元素,且不是第最后一个,则返回它的后继,否则操作失败       Insert(e):boolean         初始条件:线性表已存在(1≤i≤ListLenght(L)+1)         操作结果:在线性表L中第i个数据元素之前插入新元素e,L长度加1       Delete(e):boolean         初始条件:线性表已存在(1≤i≤ListLenght(L))         操作结果:删除线性表L中第i个数据元素,用e返回其值,L长度减1         }ADT List
';

数据结构与算法-线性表的定义与特点

最后更新于:2022-04-01 07:04:26

1.线性表概念 线性表是由零个或者多个数据元素组成的有序的序列。 图示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-03_56b207d0339ac.jpg) 2.特点 2.1 有序 我们可以从上图看见,线性表里面的元素是一个挨着一个顺序排下去的,就像平常小朋友排队等放学的样子 2.2 允许零元素,也就是空表 2.3 第一个元素有且仅有一个后继,最后一个元素有且仅有一个前驱,其他元素有且仅有一个前驱以及有且仅有一个后继 我们可以从上图看见,线性表里面第一个元素a1,他没有前驱,只有一个a2的后继,最后一个元素an,只有一个前驱a(n-1),没有对应的后继,其他某个元素ai,它有且仅有一个前驱a(i-1)以及有且仅有一个后继a(i+1)
';

数据结构与算法-如何计算时间复杂度

最后更新于:2022-04-01 07:04:23

今天我们来谈一下如何计算时间复杂度。 时间复杂度概念:(百度版) 同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。 计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。这是一个关于代表算法输入值的字符串的长度的函数。时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,它考察当输入值大小趋近无穷时的情况。 注意:本文承接上一篇《数据结构与算法-函数的渐近增长》,想详细了解渐近增长,请点击:[数据结构与算法-函数的渐近增长](http://blog.csdn.net/raylee2007/article/details/47022295) 现在先上代码,请大家详细阅读注释,因为整个计算过程都已经在注释里面体现。 ~~~ /** * 计算时间复杂度 * * @author ray * */ public class Test { private void test1(int n) { System.out.println(n);// 操作=1 } private void test2(int n) { int a = 0; for (int i = 0; i < n; i++) {// 操作=n a++;// 操作=1 } // 总操作=n*1=n // 时间复杂度=O(1) } private void test3(int n) { int a = 0; for (int i = 0; i < n; i++) {// 操作=n for (int j = 0; j < n; j++) {// 操作=n a++;// 操作=1 } } // 总操作=n*n*1=n^2 // 时间复杂度=O(n^2) } private void test4(int n) { int a = 0; for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) {// 操作=n,n-1,n-2,n-3......1=(n+1)n/2 a++;// 操作=1 } } // 总操作=(n+1)n/2=n^2/2+n/2 // 由于时间复杂度是一个抽象的概念,当n的规模达到一定程度的时候,时间复杂度只取最高次幂,而且忽略其他次要项和系数 // 时间复杂度=O(n^2) } private void test5(int n) { int a = 0; for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) {// 操作=n,n-1,n-2,n-3......1=(n+1)n/2 a++;// 操作=1 System.out.println(a);// 操作=1 // for循环内总操作=2 } } // 总操作=(n+1)n/2*2=n^2+n // 由于时间复杂度是一个抽象的概念,当n的规模达到一定程度的时候,时间复杂度只取最高次幂,而且忽略其他次要项和系数 // 时间复杂度=O(n^2) } private void test6(int n) { int a = 0; for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) {// 操作=n,n-1,n-2,n-3......1=(n+1)n/2 a++;// 操作=1 System.out.println(a);// 操作=1 System.out.println(i);// 操作=1 // for循环内总操作=3 } } // 总操作=(n+1)n/2*3=n^2*3/2+n*3/2 // 由于时间复杂度是一个抽象的概念,当n的规模达到一定程度的时候,时间复杂度只取最高次幂,而且忽略其他次要项和系数 // 时间复杂度=O(n^2) } private void test7(int n) { int a = 0; int b = 0; for (int i = 0; i < n; i++) {// 操作=n for (int j = 0; j < n; j++) {// 操作=n a++;// 操作=1 System.out.println(a);// 操作=1 // for循环内总操作=2 for (int k = 0; k < n; k++) {// 操作=n b++;// 操作=1 // for循环内总操作=1 } } } // 总操作==n^3+2n^2 // 由于时间复杂度是一个抽象的概念,当n的规模达到一定程度的时候,时间复杂度只取最高次幂,而且忽略其他次要项和系数 // 时间复杂度=O(n^3) } public static void main(String[] args) { int n = 10; Test t = new Test(); t.test1(n); t.test2(n); t.test3(n); t.test4(n); t.test5(n); t.test6(n); t.test7(n); } } ~~~
';

数据结构与算法-函数的渐近增长

最后更新于:2022-04-01 07:04:21

在说函数的渐近增长的例子前,先说说概念, **  函数的渐近增长:给定两个函数f(n)和g(n),如果存在一个整数N,使得对于所有的n > N,f(n)总是比g(n)大,那么,我们说f(n)的**渐近**增长快于g(n)。** 文字说明,比较难理解,我们利用下面的表格来说明 注意:n^2代表n 的平方,n^3代表n的立方 | 数值\函数 | n | 2n | 2n+1 | 3n+8 | n^2 | 2n^2 | 2n^2+2n+1 | n^3 | |-----|-----|-----|-----|-----|-----|-----|-----|-----| | 1 | 1 | 2 | 3 | 11 | 1 | 2 | 5 | 1 | | 2 | 2 | 4 | 5 | 14 | 4 | 8 | 13 | 8 | | 3 | 3 | 6 | 7 | 17 | 9 | 18 | 25 | 27 | | 5 | 5 | 10 | 11 | 23 | 25 | 50 | 61 | 125 | | 9 | 9 | 18 | 19 | 35 | 81 | 162 | 181 | 729 | | 10 | 10 | 20 | 21 | 38 | 100 | 200 | 221 | 1000 | | 100 | 100 | 200 | 201 | 308 | 10000 | 20000 | 20201 | 1000000 | | 1000 | 1000 | 2000 | 2001 | 3008 | 1000000 | 2000000 | 2002001 | 1000000000 | | 10000 | 10000 | 20000 | 20001 | 30008 | 100000000 | 200000000 | 200020001 | 1000000000000 | | 100000 | 100000 | 200000 | 200001 | 300008 | 10000000000 | 20000000000 | 20000200001 | 1000000000000000 | | 1000000 | 1000000 | 2000000 | 2000001 | 3000008 | 1000000000000 | 2000000000000 | 2000002000001 | 1000000000000000000 | 例如:f(n)=2n^2+1,g(n)=2n+1 当n=1是f(n)=g(n),这个时候对应上面的概念,N=1,当n>N,也就是当n>1时,f(n)>g(n),所以,我们说f(n)的渐近增加快于g(n) 同理,我们可以观察2n与2n^2 由于渐近增长是可以看作是一种抽象,所以他的对比具有一些特点: 1.注意关注函数最高次幂的变化 2.忽略次要项与乘数 为了更好理解这些特点,我做了一些图表,以便更加清楚的知道为什么 1.我们对比2n与2n+1这两个函数 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-03_56b207cf6664f.jpg) 当数值比较小的时候,两个函数之间还是存在一定的区别,但是 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-03_56b207cf9a1b9.jpg) 当输入数值非常大的时候,两条曲线基本重叠,或者可以说看作重叠,所以得出结论是,2n+1其中里面作为常数的1,在输入数值大到一定程度,他对于函数的影响可以忽略不计,这时候的1就被看作是次要项 同样,我们选择2n^2与2n^2+2n+1 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-03_56b207cfb2c4e.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-03_56b207cfcd1a8.jpg) 从上面两图可以看出,当输入数值比较小的时候,他们直接具有一定差别,但是当输入数量非常大的时候,他们两条曲线可以看作重叠,这个时候2n+1就会被看作是次要项 最后我们来看看关于乘数是次要项的例子,请看3n+8与2n^2 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-03_56b207cfeb25a.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-03_56b207d014278.jpg) 从上面的图形得出的结论与之前的一致。
';

数据结构与算法-为什么要使用算法

最后更新于:2022-04-01 07:04:19

今天来说说为什么需要使用算法? 算法是什么?算法是:指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。(百度百科版) 说完了算法的概念,我们举个例子说一下为什么需要算法? ~~~ public class Test { /** * 使用原始的循环计算等差数列 */ private void originalMethod(long n) { System.out.println("**使用原始循环算法**"); long startTime = System.currentTimeMillis(); long sum = 0; for (long i = 0; i <= n; i++) { sum += i; } long endTime = System.currentTimeMillis(); System.out.println("结果:" + sum); System.out.println("用时:" + (endTime - startTime)); } /** * 使用等差数列算法计算 * * @param n */ private void advanceMethod(long n) { System.out.println("**使用等差数列算法**"); long startTime = System.currentTimeMillis(); long sum = 0; long a1 = 1; long an = n; sum = (a1 + an) * n / 2; long endTime = System.currentTimeMillis(); System.out.println("结果:" + sum); System.out.println("用时:" + (endTime - startTime)); } public static void main(String[] args) throws InterruptedException { Test test = new Test(); long n = 1000; System.out.println("-------当n=" + n + "的时候------"); test.originalMethod(n); test.advanceMethod(n); n = 1000000; System.out.println("-------当n=" + n + "的时候------"); test.originalMethod(n); test.advanceMethod(n); n = 1000000000L; System.out.println("-------当n=" + n + "的时候------"); test.originalMethod(n); test.advanceMethod(n); } } ~~~ 输出结果: -------当n=1000的时候------ **使用原始循环算法** 结果:500500 用时:0 **使用等差数列算法** 结果:500500 用时:0 -------当n=1000000的时候------ **使用原始循环算法** 结果:500000500000 用时:3 **使用等差数列算法** 结果:500000500000 用时:0 -------当n=1000000000的时候------ **使用原始循环算法** 结果:500000000500000000 用时:2070 **使用等差数列算法** 结果:500000000500000000 用时:0 从上面的结果可以看见,使用循环算法的所用时间不断的增加,而且达到某个数量级之后(例如10的20次方),估计我们等死也等不到结果出来,而反观使用等差数列算法,使用的实际都是0,当然,其实不是0,只不过太快了,没有显示出来而已,两个计算方式相互比较一下,算法的性能一下子就看出来了。 而且对于现今大数据来说,动不动就是几亿几十亿的数据,计算的过程比我们上面的更加复杂,所需要的时间就更多,这时候如果不使用相应的算法,解决一个问题的时间基本是不可估计的,因此,我们需要算法
';

前言

最后更新于:2022-04-01 07:04:17

> 原文出处:[数据结构与算法](http://blog.csdn.net/column/details/shujujiegouyusuanfa.html) 作者:[李灵晖](http://blog.csdn.net/raylee2007) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # 数据结构与算法 > 介绍数据结构与算法
';