![](https://img-blog.csdnimg.cn/20201014180756913.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
数据结构与算法
文章平均质量分 74
iEucliwood
一位非科班程序员,正在学习中...
展开
-
Queue队列的实现
队列的基本概念及讨论队列只能在表的一端进行插入,这一端叫作队尾,而在另一端进行删除,这一端叫队头。这样的结构有先进先出FIFO(first in first off)的特点,也可以是后进后出。链表可以用来实现队列或者循环队列,数组一般用来实现循环队列,因为数组在前端的插入或删除操作花费O(N)时间。队列的应用有很多,比如打印机是按照作业到达的顺序排列起来的,生活中的排队是先到的先处理。队列的基本实现1.不循环队列基本思想如果用单链表实现,则除了链表结构外还需要多声明一个队列结构来指示在链表中的队头位置和队尾原创 2022-06-12 12:44:17 · 303 阅读 · 0 评论 -
Stack栈的实现
栈的基本概念及讨论栈只允许在固定的一端插入或者删除数据,这一端叫作栈顶,相对的另外一端就是栈底,对栈顶位的插入叫作入栈或压栈,删除叫作出栈。这样的数据结构有一个特点即后进先出LIFO(last in first off),也可以是先进后出,栈可以由数组表或者链表实现,当用数组实现时用数组的尾端作为栈顶,因为在数组尾的插入删除只需要O(1)的时间,同样若用单链表实现时,将链表头部的一端作为栈顶,也是由于O(1)的插入删除操作。栈的应用例子有很多,例如可以用于编译器判断符号是否平衡,函数调用。平衡符号若从左到右原创 2022-06-11 21:25:12 · 226 阅读 · 0 评论 -
SinglyLinkedList单链表的实现
链表允许数据不连续存储,并将每个数据链接起来,它弥补了数组表的一些局限,当需要增加一个数据时我们只需要申请存储它所需要的空间,因此不会导致空间浪费问题,并且数组表在插入数据时需要将表的部分或全部移动,花费线性时间,而链表只需要将新的数据与表链接起来即可,一般来说是在头上链接只花费常数时间,当然也有在尾上链接,此时就需要遍历链表中所有元素,花费线性时间。基本思想一个变量用于存储数据,另外一个指针用于链接下一个表元以下是结构声明与函数操作的声明为了减少指针的*号,我们可以使用typedef关键字定义类型这原创 2022-06-05 01:29:16 · 148 阅读 · 0 评论 -
SequenceList顺序表的实现
顺序表概念简单梳理与讨论顺序表即表里的元素按顺序连续存储,c语言中的内置类型数组就可以说是一个顺序表,但它不支持动态增长,此类数据结构的优点是可以随机访问表内元素,通过下标就可以直接找到顺序表中的某一元素。由于在内存中存储紧密,一般来说访问顺序表会有较好的空间局部性,访问速度较快。缺点仍然由其在存储上紧密相连的特点导致,若顺序表较大,申请内存空间会相对较长,并且此类数据结构若较多,还会引发内存碎片问题,导致一些内存浪费。另外就是顺序表的大小很可能无法提前预估,而动态开辟内存若一次开辟的较少,就可能引发频繁的原创 2022-05-31 22:54:26 · 326 阅读 · 0 评论 -
优先队列ADT--二叉堆实现
模型优先队列是允许至少下列两种操作的数据结构:Insert、DeleteMin(它的工作是找出、返回和删除优先队列中最小的元素)。Insert等价于Enqueue,DeleteMin则是队列中Dequeue的等价操作。如图大多数数据结构那样,有时可能要添加一些操作,但这些添加的操作属于扩展操作,而不属于基本模型。简单的实现一种是可以用简单链表实现,还有一种是使用二叉查找树,它对这两种操作的平均运行时间都是。记住我们删除的唯一元素是最...原创 2022-01-05 17:49:55 · 828 阅读 · 0 评论 -
散列表--双散列、再散列与可扩散列
双散列我们将要考察的最后一个冲突解决方法是双散列(double hashing)。对于双散列一种流行的选择是,意思是说冲突解决函数中又有一个对应X的散列函数,并在距离等处探测。选择不好将会是灾难性的,例如插入99,对于通常的选择将不起作用,当冲突发生时,冲突函数的值都将是0值,解决不了冲突。因此函数一定不要算得0值。 诸如这样的函数将起到良好的作用,其中R为小于tableSize的素数。使用双散列时保证表的大小为素数时重要的,假设选取R为7,表大小为10。若想把23插入...原创 2022-01-04 22:15:54 · 3844 阅读 · 1 评论 -
散列表ADT--开放定址法
分离链接散列算法的缺点是需要指针,由于给新单元分配地址需要时间,因此这就导致算法的速度多少有些减慢,开放定址散列法(open addressing hashing)是另外一种用链表解决冲突的方法。在开放定址散列算法系统中,如果有冲突发生,那么就要尝试选择另外的单元,直到找出空的单元为止。更一般地,单元相继试选,其中 ,且。函数F是冲突解决方法。因为所有的数据都要置入表内,所以开放定址散列法所需要的表要比分离链接散列用的表大。一般来说,对开放定址散列算法来说,装填因子应该低于=0.5。 线性...原创 2022-01-03 20:39:03 · 447 阅读 · 0 评论 -
散列表ADT--分离链接法
分离链接法解决冲突的第一种方法通常叫作分离链接法(separate chaining),其做法是将散列到同一个值的所有元素保留在一个表中。为方便起见这些表都有表头。如果空间很紧,则更可取的方法是避免使用这些表头。(分离链接法的意思,个人理解为将散列表与关键字分离开,关键字值存在表里然后将它们链接起来,因为后面可以看到访问关键字时,是先找到散列表再通过散列表中存储的其他表的地址找到表并在表里去访问关键字,因为是指针或许也可以说成先找到散列表,再通过散列表链接的其他表去访问关...原创 2022-01-02 00:25:43 · 1021 阅读 · 0 评论 -
散列表--散列函数
一般想法理想的散列表数据结构只不过是一个含有关键字的具有固定大小的数组。典型情况下,一个关键字就是一个带有相关值(例如工资信息)的字符串。我们把表的大小记作 tableSize,并将其理解为散列数据结构的一部分,而不仅仅是浮动于全局的某个遍历。通常的习惯是让表从0到tableSize-1变化。将每个关键字映射到从0到tableSize-1这个范围中的某个数,并且放到适当的单元中。这个映射叫作散列函数(hash function),理想情况下它应该运算简单并且应该保证任何两个不同的关键...原创 2022-01-01 20:46:02 · 537 阅读 · 0 评论 -
B树查找树
B树 有一种常用的查找树不是二叉树,这种树叫作B树(B-tree) 阶为M的B树具有下列结构特性: ·树的根或者是一片树叶,或者其儿子数在2和M之间。 ·除根外,所有非树节点的儿子数在[M/2]和M之间。 ·所有的树叶在相同的深度上。 所有的数据都存储在树叶上。在每一个内部节点上皆含有指向该节点各儿子的指针和分别代表在子树中发现的最小关键字的值。当然,可能有些指针是NULL,而其对应的...原创 2022-01-01 17:09:41 · 498 阅读 · 0 评论 -
伸展树与树的遍历
现在我们描述一种相对简单的数据结构,叫作伸展树(splay tree),它保证从空树开始任意连续M次对树的操作最多花费时间。虽然这种保证并不排除任意一次操作花费时间的可能,而且这样的界也不如每次操作最坏情形的界那么短,但是实际效果是一样的--不存在坏的输入序列。一般说来,当M次操作的序列总的最坏情形运行时间为时,我们就说它的摊还(amortized)运行时间为。因此,一棵伸展树每次操作的摊还代价是。经过一系列操作之后,有的可能花费时间多一些,有的可能要少一些。...原创 2021-12-31 00:16:46 · 249 阅读 · 0 评论 -
AVL树--单旋转、双旋转与实现
AVL树AVL(Adelson-Velskii andLandis)树是带有平衡条件的二叉查找树。必须保证树的深度是。 最简单的想法是要求左右子树具有相同的高度。 另一种平衡条件是要求每个节点都必须要有相同高度的左子树和右子树。如果空子树的高度定义为-1(通常就是这么定义的),那么只有具有个节点的理想平衡树(perfectly balanced tree)满足这个条件。因此虽然这种平衡条件保证了树的深度小,但是它太严格,难以使用需要放...原创 2021-12-29 23:00:25 · 1014 阅读 · 0 评论 -
查找树ADT--二叉查找树与平均情形分析
二叉树的一个重要的应用是它们在查找中的使用。假设给树中的每个节点指定一个关键字值。为简单起见假设它们都是整数。还假设所有的关键字是互异的。 使二叉树成为二叉查找树的性质是,对于树中的每个节点X,它的左子树中所有的关键字值小于X的关键字值,而它的右子树中所有关键字值大于X的关键字值。注意这意味着该树所有的元素可以用某种统一的方式排序。 由于树的递归定义,通常是递归地编写这些操作的例程。因为二叉查找树的平均深度是,所以我们一般不必担心栈空间被用尽。 ...原创 2021-12-27 22:28:58 · 426 阅读 · 0 评论 -
二叉树--实现与构造表达式树
二叉树二叉树(binary tree)是一棵树,其中每个节点的儿子都不能多于两个。二叉树的一个性质是平均二叉树的深度要比N小得多,这个性质有时很重要。分析表明这个平均深度为,而对于特殊类型的二叉树,即二叉查找树(binary search tree),其深度的平均值是。不幸的是,这个深度是可以大到N-1的。 实现因为一棵二叉树最多有两个儿子,所以我们可以用指针直接指向它们。在声明中,一个节点就是由 key(关键字)信息加上两个指向其他...原创 2021-12-26 19:26:24 · 664 阅读 · 0 评论 -
树-预备知识、实现、遍历及应用
预备知识 定义树的一种自然的方式是递归法。一棵树是一些点的集合。这个集合可以是空集;若非空,则一棵树由称作根(root)的节点 r 以及0个或多个非空的(子)树原创 2021-12-26 16:00:01 · 219 阅读 · 0 评论 -
队列ADT--链表实现与数组实现
像栈一样,队列(queue)也是表。然而,使用队列时插入在一端进行而删除则在另一端进行。 队列模型 队列的基本操作是 Enqueue(入队)-- 在表的末端(叫作队尾(rear))插入一个元素,还有Dequeue(出队)-- 删除(或返回)在表的开头(叫作队头(front))的元素。 队列的链表实现 对于链表实现队列,我们要使用循环链表,这是为了保证每个操作都是运行时间。否则入队需要时间。 类型声明......原创 2021-12-25 18:45:37 · 884 阅读 · 0 评论 -
栈的四个应用
平衡符号每个右花括号,右方括号及右圆括号必然对应相应的左括号。序列“[ ( ) ]”是合法的,“ [ ( ])“ 是错误的。 显然也不值得为此编写一个大型程序。事实上检验这些是很容易的,为简单起见我们仅就圆括号、方括号和花括号进行检验,并忽略其他字符。 这个简单的算法用到一个栈,叙述如下: 做一个空栈。读入字符直到文件尾。如果字符是一个开放字符(即左符号),将其推入栈中。如果字符是一个封闭符号(即右符号),则当栈空时报错...原创 2021-12-25 12:37:03 · 4845 阅读 · 0 评论 -
栈ADT--链表实现与数组实现
栈模型栈是限制插入和删除只能在一个位置上进行的表,该位置为表的末端,叫做栈顶(top)。对栈的基本操作有 Push(进栈)和Pop(出栈),前者相当于插入后者相当于删除。 栈有时又叫做LIFO(后进先出-last in first out)。普通的清空栈的操作和判断是否空栈的测试都是栈的操作指令系统的一部分,但是对栈能够做的基本上也就是 Push 和 Pop 操作,也就是说清空栈是通过 Pop 操作来完成的,它没有操作栈,...原创 2021-12-23 23:19:35 · 499 阅读 · 0 评论 -
链表的游标实现
有许多语言都不支持指针,若需要链表又不能使用指针,就必须用另外的实现方法。我们称之为 游标(cursor)实现法。链表的指针实现中有两个重要特性: 1.数据存储在一组结构体中,每个结构体包含数据以及指向下一个结构体的指针。 2.一个新的结构体可以通过调用malloc而从系统全局内存(global memory)中得到,并可通过调用free释放。 游标法必须能够模仿实现这两条特性。满足条件1的逻辑方法是要有一...原创 2021-12-22 21:31:54 · 861 阅读 · 1 评论 -
链表--扩展讨论与多项式ADT
常见错误 最常遇到的错误是程序崩溃,这通常意味着指针变量包含了伪地址,一个通常原因是未初始化变量,另一个原因是寻找非法的指向,如NULL。前一篇文章若传的参数为NULL,则程序会崩溃,当然我们如此写例程是知道参数不会为NULL的,不过我们还是得确保例程能够处理这一情况。所以在每个例程开始时 检查参数 也是我们要考虑的事。 其次是malloc的使用,要知道声明一个指向该结构的指针并不会创建该结构,当我们想要创建一个链表时,我们可以先声明指向表头结构的指针...原创 2021-12-21 23:22:19 · 222 阅读 · 0 评论 -
链表--基本实现
数组表的局限数组实现的表虽然能动态指定,但仍需要对表大小的最大值进行估计,通常需要估计得大一些,而这会浪费大量空间。而且插入和删除得花费是昂贵的,因为需要将部分元素或全部元素都前移或者后移。如果通过N次插入来建立一个表将需要二次时间。 链表为了避免了插入和删除的线性开销和空间的浪费,我们允许表可以不连续存储,否则表的部分或全部需要整体移动。链表由一系列不必在内存中相连的结构组成。每个结构均含有表元素和指向该元素后继...原创 2021-12-20 20:44:11 · 288 阅读 · 0 评论 -
二分查找 欧几里得算法 幂运算
二分查找(binary search)给定一个整数和整数,后者已经预先排序并在内存中,求是的的下标,如果不在数据种,则返回。int BinarySearch(const int arr[], int size, int x){ int left, right, mid; left = 0; right = size - 1; while (left <= right) { mid = (left + right) / 2; if (x &...原创 2021-12-19 23:03:50 · 85 阅读 · 0 评论 -
最大子序列和
前言:若有不懂处欢迎评论区留言算法1:穷举式地尝试所有的可能int MaxSubsequenceSum(const int arr[], int size){ int thisSum, maxSum, i, j, k; maxSum = 0; for (i = 0; i < size; i++) for (j = i; j < size; j++) { thisSum = 0; for (k = i; k <= j; k++) { t原创 2021-12-19 20:00:36 · 273 阅读 · 0 评论