- 博客(43)
- 收藏
- 关注
原创 二叉排序树的创建和基本操作---C++实现
本文介绍了二叉排序树的基本概念和实现方法。二叉排序树是一种特殊的二叉树,其左子树所有结点值小于根结点,右子树所有结点值大于根结点。文章详细展示了二叉排序树的C++代码实现,包括初始化、插入、构建、查找、删除等操作。其中查找操作时间复杂度最好为O(log2n),最坏为O(n)。删除操作考虑了三种情况:叶子结点、单支结点和双支结点。通过代码示例演示了二叉排序树的基本操作和特性。
2025-12-08 23:38:44
256
原创 顺序查找---C++实现
顺序查找是最基础的查找算法,通过遍历顺序表或链表寻找目标值。常规方法采用for循环逐个比较元素,找到则返回下标,未找到返回-1。改进方法使用哨兵技术,将目标值置于数组首位后从后向前遍历,减少越界风险,返回0表示未找到。两种方法的时间复杂度均为O(n)。
2025-12-01 20:18:59
200
原创 折半查找(二分查找)
摘要:本文介绍了折半查找(二分查找)算法,适用于有序顺序表。该算法通过比较中间元素与目标值,不断缩小查找范围,最终定位目标元素或确认其不存在。文中提供了C语言实现代码,并指出其时间复杂度为O(log2n)。折半查找比顺序查找更高效,但不适用于无序数据或链表结构。
2025-11-30 11:26:28
185
原创 拓扑排序的实现
本文介绍了图的拓扑排序算法及其实现。拓扑排序是一种对有向无环图顶点进行排序的方法,要求顶点序列满足:每个顶点出现一次,且若A在B前则图中不存在B到A的路径。实现步骤包括选择入度为0的顶点输出,删除该顶点及其邻接边,重复直到图为空或没有无前驱顶点。文中提供了完整的C语言代码实现,使用邻接表存储图结构,通过栈处理顶点排序过程,并分析了算法的时间复杂度(邻接表为O(|V|+|E|),邻接矩阵为O(|V|²))。最后展示了程序运行结果,验证了拓扑排序的正确性。
2025-11-05 21:02:10
890
原创 Floyd算法
本文介绍了Floyd算法用于求解图中任意两点间的最短路径。该算法基于动态规划思想,通过逐步引入中转点来更新最短路径。文章详细说明了算法实现过程:初始邻接矩阵存储路径长度,path数组记录中转点。核心操作通过三重循环比较路径长度,当发现更短路径时更新邻接矩阵和path数组。代码示例展示了创建4顶点有向图、初始化邻接矩阵、执行Floyd算法并输出结果的完整实现。算法时间复杂度为O(n³),空间复杂度为O(n²)。文中特别提醒处理无直接路径时需注意整数溢出的问题。
2025-10-31 19:37:34
827
原创 Dijkstra算法
本文介绍了图的最短路径算法。Dijkstra算法用于求解单源最短路径,通过维护final、dist、path三个数组,采用贪心策略逐步确定各顶点的最短路径,时间复杂度为O(n²)。Floyd算法则用于求解两点间最短路径。文章详细演示了Dijkstra算法的手算过程,包括初始化数组、寻找最小dist值、更新邻接顶点距离等步骤,并以具体图例展示了如何通过回溯path数组找到完整路径。这种算法弥补了广度优先遍历无法处理带权图的局限性。
2025-10-30 18:55:37
342
原创 最短路径——BFS
本文介绍了在无权图中使用广度优先搜索(BFS)算法求解单源最短路径的方法。通过维护两个数组d[]和path[]分别记录路径长度和前驱顶点,实现了从源点到各顶点的最短路径计算。文章详细展示了图的邻接表存储结构、队列操作实现以及BFS遍历的核心代码,并演示了如何输出特定顶点对(A到E)的最短路径。最后指出该方法仅适用于无权图,并预告后续将介绍适用于带权图的Dijkstra算法。该实现充分体现了BFS"层层推进"的特性,确保找到的路径是最短的。
2025-10-27 20:48:03
447
原创 图的深度优先遍历
本文介绍了图的深度优先遍历(DFS)算法实现。与树的先根遍历类似,DFS通过递归访问邻接点实现,但需设置标记数组避免重复访问。文章提供了完整的C语言代码实现,包括图结构定义、顶点和边的插入、邻接点查找等核心函数。代码采用邻接表存储结构,通过递归实现DFS遍历,并分析了算法的时间复杂度:邻接矩阵为O(|V|²),邻接表为O(|V|+|E|);空间复杂度主要来自递归栈,为O(|V|)。该实现为图的深度优先搜索提供了清晰的编程范例。
2025-10-25 14:56:47
1201
原创 图的广度优先遍历
本文介绍了图的广度优先遍历(BFS)算法实现。BFS使用辅助队列,通过访问顶点及其邻接点实现层次遍历。文章详细讲解了算法思想,包括邻接点查找、访问标记数组的使用,并提供了基于邻接表的完整C语言代码实现(含图结构定义、队列操作、BFS核心算法等)。代码实现了图的初始化、顶点/边插入、邻接点查找等功能,并通过队列完成BFS遍历。分析指出该算法空间复杂度为O(|V|),时间复杂度为O(|V|+|E|),若使用邻接矩阵则时间复杂度变为O(|V|²)。结果不唯一性与邻接表存储特性有关。
2025-10-23 19:54:49
851
原创 邻接矩阵的基本操作
NextNeighBor(G,x,y):假设图G中顶点y是顶点x的一个邻接点,返回除y之外顶点x的下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1。若x没有邻接点或图中不存在x,则返回-1。//假设图M中顶点y是顶点x的一个邻接点,返回除y外顶点x的下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1。RemoveEdge(G,x,y):若无向边(x,y)或有向边<x,y>存在,则从图G中删除该边。AddEdge(G,x,y):若无向边(x,y)或有向边<x,y>不存在,则向图中添加该边。
2025-10-17 20:46:44
647
原创 十字链表的构建和操作
本文介绍了十字链表法这一优化邻接表存储有向图的算法。针对邻接表查找入度效率低的问题,十字链表通过顶点结构体同时存储第一条入度和出度边,边结构体则包含弧头、弧尾及指向同弧头/弧尾的下一条边的指针。代码实现包括初始化图、添加顶点和边,以及查询顶点出入度的功能。该算法的时间复杂度为O(|V|+|E|),空间复杂度O(n),有效解决了邻接表在处理有向图时的效率问题。
2025-10-14 20:55:34
1125
原创 用邻接表构建图
本文介绍了图的邻接表存储方法,相比邻接矩阵更节省空间,特别适合稀疏图。邻接表通过数组存储顶点数据,用链表存储邻接边,类似树的孩子结点存储法。文中给出了详细的C语言实现代码,包括图结构体定义、初始化、顶点和边的插入操作,以及遍历邻接顶点的功能。通过示例展示了如何构建邻接表并查询顶点度数和邻接关系。该方法在空间利用率和稀疏图处理效率上具有明显优势。
2025-10-13 17:26:48
651
原创 邻接矩阵的创建和基本操作
本文介绍了邻接矩阵的图存储实现方法。通过定义MGraph结构体存储顶点集和边矩阵,使用一维数组保存顶点,二维数组保存边关系。文章详细说明了图的初始化、顶点/边创建、度数查询和顶点删除等操作的C语言实现,并分析了时间复杂度O(n)和空间复杂度O(n²)的特性。这种基于邻接矩阵的存储方式适用于需要频繁查询边关系的图结构应用场景。
2025-10-12 15:52:31
469
原创 并查集的优化
本文介绍了一种优化后的并查集算法实现。通过改进Find函数,在查找时进行路径压缩(将路径上的节点直接连接到根节点),使得在频繁调用Find和Union操作时,时间复杂度显著降低。Find操作的时间复杂度为O(α(n)),Union操作为O(nα(n)),其中α(n)是阿克曼函数的反函数,增长极其缓慢。即使n达到宇宙原子数量级(10^80),Find操作的时间复杂度也不会超过O(5)。
2025-10-06 16:02:22
576
原创 并查集的实现
本文介绍了并查集数据结构的C语言实现。并查集用于处理不相交集合的合并和查询操作,通过森林结构表示。核心操作包括初始化集合(Initial)、插入节点(EnNode)、建立链接(EstablishLink)、查找根节点(Find)和合并集合(Union)。Find函数通过向上查找确定元素所属集合,Union函数根据集合大小进行合并优化。示例代码展示了如何初始化13个节点(A-M),构建三棵树结构,并通过Union操作合并集合。该实现采用按大小合并策略,提高了算法效率。
2025-10-05 18:47:34
444
原创 树的存储结构
printf("%d的孩子结点为%d\n", n, Tree->arr[p->place].data);printf("%d的父结点为%d\n", n, Tree->arr[i].data);printf("%d的孩子结点为%d\n", n, tree->arr[i].data);//找孩子结点,假设寻找结点元素为4的孩子结点。//寻找父结点,假设寻找结点元素为4的父亲结点。printf("%d的孩子结点为%d\n", n, s->data);每个结点中保存数据元素、指向双亲结点(父结点)的指针。
2025-09-30 17:54:01
495
原创 线索二叉树寻找前驱和后继
/左孩子的最后一个节点为前驱。if (start <= end && temp->lchild == NULL)//创建左孩子。if (start <= end && temp->rchild == NULL)//创建右孩子。if (Public->lchild->ltag == 1)//证明左孩子为叶子结点。if (T->rchild->rtag == 1)//证明右孩子是叶子结点。
2025-09-23 22:56:15
916
1
原创 线索二叉树的创建
if (start <= end && temp->lchild == NULL)//创建左孩子。if (start <= end && temp->rchild == NULL)//创建右孩子。bool DeQueue(SQueue* Q, ThreadNode** temp)//队列出队。bool EnQueue(SQueue* Q, ThreadNode* T)//入队。
2025-09-22 13:05:32
793
原创 完全二叉树的链式创建以及遍历(优化新增)
if (start <= end && temp->Lchild == NULL)//插入左孩子。if (start <= end && temp->Rchild == NULL)//插入右孩子。bool DeQueue(SQueue* Q, TreeNode** temp)//出队。bool EnQueue(SQueue* Q, TreeNode* temp)//入队。//根结点指向左孩子。
2025-09-20 10:16:24
802
原创 完全二叉树的链式创建以及遍历
思想:完全二叉树的思想利用了层次遍历的思想,已经队列的辅助来创建,当我们创建根结点需要建立左右孩子结点的时候,只需要把根结点入队,根据出队的结点来判断左右孩子是否为空,再创建左右孩子结点。if (start <= end && temp->Lchild == NULL)//插入左孩子。bool DeQueue(SQueue* Q, TreeNode** temp)//出队。
2025-09-19 13:28:35
661
原创 二叉树的顺序存储
bool InsertTree(TreeNode t[], int arr[],int * length)//插入数据。bool FindFatherNode(TreeNode t[], int i)//查找i结点的父结点。bool FindRightSon(TreeNode t[], int i)//查找结点i的右孩子。bool FindLeftSon(TreeNode t[], int i)//查找结点i的左孩子。bool FindFloor(TreeNode t[], int i)//返回所在层数。
2025-09-14 21:50:56
895
原创 串的模式匹配(朴素算法和KMP算法以及KMP的改进算法)
3.其他的next在不匹配的位置前,划一条分界线,模式串一步一步往后退,知道分界线之 前 “能对上”,或模式串完全跨过分界线为止。如果当前失败的元素与下一个要比较的元素的一样的话,我们可以直接令当前失败的元素直接指向下一次要比较的元素下标。if (S[x] == S[next[x]])//如果当前的数与下一个数相等的话。//如果不相等直接赋值。如果当前匹配失败的这个元素,与next[j]指向的下一个元素一样的话。
2025-09-09 15:52:39
850
1
原创 顺序串基本功能的实现
int StrCmp(SString S, char* arr)//串比较,如果串1 > 串2直接返回 > 0,如果串1 = 串2 则返回 = 0,如果串1 < 串2 则返回 < 0;bool SubString(SString* Sub, SString S, int pos, int len)//求子串,用Sub返回串S中第pos个字符开始长度为len的子串。int StrIndex(SString S, char* arr)//求子串,如果主串中存在与Q相同的子串,则返回子串的首个位置,否则返回零。
2025-09-07 18:50:44
727
原创 假设一个算术表达式中包含圆括号、方括号和花括号3种类型的括号,编写一个算法来判别,表达式中的括号是否配对,以字符“\0“作为算术表达式的结束符
else if (EmptyStack(*S) == true && (*a == ')' || *a == ']' || *a == '}'))//如果栈为空,且字符串中还有元素。else if (EmptyStack(*S) == false && *a == ')' && GetTop((*S))->data == '(')//如果是'('则出栈。= '(')//如果不是则直接退出。if (*a == '(' || *a == '[' || *a == '{')//如果当时是三个括号其中一个则入栈。
2025-09-05 21:08:03
864
原创 //Q是一个队列,S是一个空栈,实现将队列中的元素逆置的算法。
/假设要输入1,2,3,4,5,6。int* DeQueue(LinkQueue* Q, int* x)//出队。bool EnQueue(LinkQueue* Q, int x)//入队。bool Push(LinkStack** S, int x)//进栈。if (Q->front == Q->rear)//空队。if (Q->front == NULL)//分配失败。if (p == Q->rear)//恰好有一个元素。if (q == NULL)//分配失败。
2025-08-29 17:47:20
744
原创 链式队列的实现和操作
bool DestoryQueue(LinkQueue* Q)//销毁队列。if (Q->front->next == NULL)//空队。if (Q->front->next == NULL)//为空。if (Q.front->next == NULL)//空队。if (Q.front->next == NULL)//空队。if (Q->front == NULL)//空队无法出队。
2025-08-28 11:19:42
799
原创 顺序队列的常见的三种创建和操作方法
if ((Q->rear+1) % MaxSize == Q->front)//利用取模判断是否栈满。//增加tag = 0/1用于标记最近一次的操作是出队/入队(0 -> 出队,1 -> 入队)if (Q.tag == 1 && Q.front == Q.rear)//满栈的情况。if (Q->front == Q->rear)//如果两个指针在相同的位置则为空队。if (Q.tag == 0 && Q.front == Q.rear)//空队。
2025-08-27 14:42:43
343
原创 栈的创建和基本操作
if (S->top == MaxSize)//满栈了,第二次插入数据后满栈返回true。if (S->top == MaxSize)//满栈,第一次满栈插入不了任何数据返回false。int GetTop(Sqstack S, int* x)//查找栈顶元素。if (n > S->top)//如果出栈个数大于总个数直接返回。if (S->top == 0)//空栈。if (S->top == 0)//空栈。if (S.top == 0)//空栈。if (S.top == 0)//空栈。
2025-08-24 09:38:25
1030
原创 线性表交叉排序
bool InsertList(NODE** L, int arr[])//插入。bool InitList(NODE** L)//初始化。bool Arrange(NODE** L)//交叉排序。bool PrintList(NODE* L)//打印。
2025-08-23 15:13:18
713
原创 用单链表保存m和整数,结点的结构为[data][link],且[data] <= n(n为整数)。对于链表中data的绝对值相等的结点仅保留第一次出现的结点而删除其余绝对值相等的结点。
else if (arr[abs(p->data)] == 1)//如果等于1则代表p->data已经出现过。if (arr[abs(p->data)] == 0)//查找p->data下标所在的数值是否为0。bool FindSame(LinkList L)//寻找并删除绝对值相同的元素。bool InsertList(LinkList* L, int m)//插入。bool InitList(LinkList* L)//初始化。bool PrintList(LinkList L)//打印。
2025-08-22 19:06:24
762
原创 //单链表有环,是指单链表的最后一个结点的指针指向了链表中的某个结点(通常单链表的最后一个结点的指针域是空的)//试编写算法判断单链表是否存在环,如果带环则找出环的起点
/ 具体:设表头到环的距离为L,设快指针与慢指针相遇的结点为x,从两指针相遇的结点到起点为y,设一圈的距离为R。if (fast->next == NULL || fast->next->next == NULL)//不带环的情况。// 则慢指针一共移动了L+x个结点,快指针则移动了2(L+x)个结点,快指针比慢指针多走了n圈。// (n-1)R可以当做0,(R+x)=y L = y。// 1.设置快慢指针,其中快的走两个结点慢的走一个结点。
2025-08-21 08:38:38
539
原创 //设将n(n > 1)个整数存放到不带头结点的单链表L中,设计算法将L中保存的序列循环右移k(0 < k < n)个位置//例如,若k = 1,则将链表{0,1,2,3}变成{3,0,1,2}。
bool RightMove(LinkList* L, int x)//右移。//(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。= 9999)//假设输入9999退出。bool InitList(LinkList* L)//初始化。bool InsertList(LinkList*L)//插入。//头结点L指向新的位置。bool PrintList(LinkList L)//打印。int Lenth(LinkList L)//计算长度。//(3)说明你设计算法的时间复杂度和空间复杂度。
2025-08-20 17:10:41
333
原创 //设有一个带头结点的非循环双链表L,其每个节点中除了有pre,data和next域外,还有一个访问频度域的freq,其值初始化为零,每当链表中进行一次Locate(L,x)运算时,令值为x的结点
LNode* Locate(LinkList* L, int x)//查找函数。if (p->next == NULL)//如果是最后一个元素。= NULL)//当p要插入的不是最后一个。bool InsertList(LinkList* L)//插入。bool PrintList(LinkList L)//打印函数。bool InitList(LinkList* L)//初始化。if (q == NULL)//p插入的是最后一个元素。if (p == NULL)//如果找不到直接返回空。
2025-08-19 18:10:33
792
原创 //已知两个链表A和B分别表示两个集合,其元素递增排列。编写函数,求A与B的交集,并存放与A链表中(A链表中只存放交集)
bool Intersection(LinkList* L1, LinkList L2)//找交集(归并思想)else if (q->data < p->data)//如果链表B元素小于链表A元素。if (p->data < q->data)//如果链表A元素小于链表B元素。bool InsertList(LinkList* L)//插入数据。bool InitList(LinkList* L)//初始化。//插入B链表中的数据。bool PrintList(LinkList L)//打印。
2025-08-18 08:58:11
382
原创 设C={a1,b1,a2,b2....an,bn}为线性表,采用带头结点的单链表存放//设计一个就地算法,将其拆分为两个线性表,使得A={a1,b1...,an},B={bn...,b2,b1}
bool SplitList(int arr[], LinkList* L1, LinkList* L2)//拆分并插入。//假设线性表为{10,20,30,40,50,60,70,80,90,100}SplitList(arr, &L1, &L2);bool PrintList(LinkList L)//打印函数。//p作为L1的尾指针。if ((*L) == NULL)//分配空间失败。
2025-08-17 11:13:34
1246
原创 在带头结点的单链表L中,删除所有值为x的结点,并释放其空间,假设值为x的结点不唯一//试编写算法以实现上述操作
/插入数据且假设输入10 20 30 30 40 30。bool DeleteList(LinkList* L, int x)//删除。i++)//假设有6个结点。bool Insert_tail(LinkList* L)//插入。bool InitList(LinkList* L)//初始化。bool PrintList(LinkList L)//打印。//指向头结点的指针。
2025-08-16 12:39:49
552
原创 双链表基本功能的实现
bool InsertNode_front(LinkList* L, int z, int z1)//前插操作。bool InsertLNode_tail(LinkList* L,int n,int n1)//后插操作。void InitNode_tail(LinkList* L)//初始化插入(尾插法)void InitNode_head(LinkList* L)//初始化插入(头插法)
2025-08-12 10:02:13
711
原创 单链表基本功能的实现(优化)
bool Front_InserLNode(LinkList* L,int n2,int n3)//前插操作。bool InsertLNode(LinkList* L,int i, int n1)//后插操作。//LinkList LocalElem(LinkList L, int n6)//按值查找。void InitData_head(LinkList* L)//头插法(实现逆序)//InitData_head(&L);
2025-08-11 14:56:50
670
原创 单链表基本功能的实现
bool Front_InserLNode(LinkList* L,int n2,int n3)//前插操作。bool InserLNode(LinkList* L,int i, int n1)//后插操作。//LinkList LocalElem(LinkList L, int n6)//按值查找。bool DeleteLNode(LinkList * L,int n4)//删除。//把要插入的数传给p结点。
2025-08-10 13:11:38
536
原创 已知一个整数序列 A=(a0,a1,a2...an-1),其中0 <= ai < n(0 <= i < n).若存在ap1=ap2=...apm=x且m>n/2(0 <= pk < n,1 <= k
把一个元素当成一个候选人,出现的次数当成投的票数,通过遍历整个数组,如果候选人不一样的话;if (candidate == L1->data[i])//如果两个元素一样的话,令票数+1。本题讨论一个数组中元素出现的次数,如果一个元素出现的次数大于长度的一半时,此时称这个元素为主元素。今天给大家介绍一种时间复杂度为O(n),空间复杂度为O(1)的算法,摩尔投票法。排序法的时间复杂度为O(nlogn),空间复杂度为O(1),显然也不是最优解。哈希表的时间复杂度和空间复杂度均为O(n),显然不是最优解。
2025-08-08 11:17:28
706
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅