数据结构
瓴翎玲
一点一滴积累,一步一步向前
展开
-
组队竞赛
链接:https://www.nowcoder.com/questionTerminal/6736cc3ffd1444a4a0057dee89be789b?orderByHotValue=1&page=1&onlyReference=false来源:牛客网题目描述牛牛举办了一次编程比赛,参加比赛的有3*n个选手,每个选手都有一个水平值a_i.现在要将这些选手进行组队,一共组成n个队伍,即每个队伍3人.牛牛发现队伍的水平值等于该队伍队员中第二高水平值。例如:一个队伍三个队员的水平值分原创 2021-10-13 21:44:39 · 53 阅读 · 0 评论 -
堆排序算法
思想://堆排序void AdjustDown(int* a, int n, int root){ int parent = root; int child = parent * 2 + 1; //左孩子 while (child < n) { //先检查是否越界再判断 if (child + 1 < n && a[child + 1] > a[child]) { ++child; //如果右孩子更大,则child变为child+1原创 2021-05-25 20:11:42 · 51 阅读 · 0 评论 -
冒泡排序算法
思想://最好:O(N)//最坏:O(N^2)void BubbleSort(int* a, int n){ for (int end = n; end > 0; --end) { int exchange = 0; for (int i = 1; i < end; ++i) { if (a[i - 1] > a[i]) { Swap(&a[i - 1], &a[i]); exchange = 1; } }原创 2021-05-25 19:55:12 · 54 阅读 · 0 评论 -
选择排序算法
思想://选择排序void SelectSort(int* a, int n){ int left = 0, right = n - 1; while (left < right) { //选出最大的值和最小的值 int minIndex = left, maxIndex = left; for (int i = left; i <= right; ++i) { if (a[i] < a[minIndex]) minIndex = i; i原创 2021-05-25 19:47:47 · 139 阅读 · 0 评论 -
希尔排序
思想:先分组,对分组的数据进行插入排序(1)预排序:接近有序(2)直接插入排序间隔为gap分成一组,对一组进行插入排序注意:gap越大,大的和小的数可以更快地挪到对应的方向去,但是越不接近有序,gap = 1,直接就是插入排序void ShellSort(int* a, int n){ //gap大于1,则为预排序,gap == 1,插入排序 int gap = n; while (gap > 1) { gap = (gap / 3 + 1); //+1:保证最后一个一定为1原创 2021-05-24 21:51:12 · 50 阅读 · 0 评论 -
插入排序
思想:void InsertSort(int* a, int n){ //多趟排序 for (int i = 0; i < n - 1; i++) { //把tmp插入到数组的[0,end]有序区间中 int end = i; int tmp = a[end + 1]; while (end >= 0) { if (tmp < a[end]) { a[end + 1] = a[end]; //end往后挪一个位置 --end;原创 2021-05-24 21:28:48 · 35 阅读 · 0 评论 -
翻转二叉树
思路:递归遍历先判断结点是否为空,若不为空,则交换结点的左右孩子的值,交换后,再交换左右子树。struct TreeNode* invertTree(struct TreeNode* root){ if(root == NULL) return NULL; struct TreeNode* left = invertTree(root->left); struct TreeNode* right = invertTree(root->right);/原创 2021-05-18 21:38:38 · 52 阅读 · 0 评论 -
排序算法的总结
稳定性:在数组中,相同的数据原创 2021-05-15 15:46:29 · 37 阅读 · 0 评论 -
计数排序
思想:(1)统计相同元素出现的次数(2)根据统计的结果将序列回收到原来的序列中绝对映射A[i]是几就对count数组位置的值加1(计算次数)for(int i = 0; i < n; i++) count[A[i]]++;相对映射若还是从0-15,会造成空间浪费,直接从0开始,10对应0,11对应1……for (int i = 0; i < n; i++) { count[a[i] - min]++; //映射到相对位置 }void CountSort(in原创 2021-05-15 10:25:46 · 47 阅读 · 0 评论 -
归并排序的递归与非递归方法
递归思想:借助临时创建的数组,对进行排序的数组进行两两归并,最后排完序再拷贝回原数组。void _MergeSort(int* a, int left, int right,int* tmp){ if (left >= right) return; int mid = (left + right) >> 1; //[left, min][mid+ 1,right] _MergeSort(a, left, mid, tmp); _MergeSort(a, mid +原创 2021-05-15 09:55:40 · 89 阅读 · 0 评论 -
快速排序的3种递归方法及非递归方法
前后指针法cur与prev开始一前一后,cur去找比keyi位置小的值,找到小的值以后,++prev,再交换prev和cur位置的值,直到数组尾,最后,交换keyi与prev的值原创 2021-05-14 15:51:30 · 760 阅读 · 0 评论 -
二叉树最大深度
二叉树最大深度二叉树的深度为根节点到最远叶子节点的最长路径上的节点数 struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; };int maxDepth(struct TreeNode* root){ if(root == NULL) return 0; int leftDepth = maxDepth(root->left);原创 2021-05-09 19:22:52 · 51 阅读 · 0 评论 -
单值二叉树
单值二叉树所有结点值一样的二叉树为单值二叉树struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right;};bool isUnivalTree(struct TreeNode* root){ if(root == NULL) return true; if(root->left && root->left->val != root-&原创 2021-05-09 19:19:04 · 103 阅读 · 0 评论 -
二叉树的基本操作
定义二叉树原创 2021-05-09 19:14:32 · 55 阅读 · 0 评论 -
最小的K个数
最小的K个数输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。思路:针对海量数据(1)先把数组中前K个数据建成大堆(2)然后剩下的N-K个数跟堆顶数据比较,若比堆顶数据小,则替换堆顶的数据,调整堆(3)最后堆里面就是最小的K个数时间复杂度:O(N*logK)空间复杂度:O(K)说明:以下程序中出现的程序调用函数均出现在堆的基本操作中//时间复杂度:O(N*logK) 空间复杂度:O(K)int*原创 2021-05-03 19:11:34 · 100 阅读 · 0 评论 -
堆的基本操作
堆的定义typedef int HPDataType;struct Heap{ HPDataType* a; //数组的形式存储 int size; int capacity; //插入空间不够,需要扩容};typedef struct Heap HP;堆的初始化void HeapInit(HP* php, HPDataType* a, int n){ assert(php); php->a = (HPDataType*)malloc(sizeof(HPDataTy原创 2021-05-03 16:31:18 · 63 阅读 · 1 评论 -
设计循环队列
设计循环队列实现循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。你的实现应该支持如下操作:MyCircularQueue(k): 构造器,设置队列长度为 k 。Front: 从队首获取元素。如果队列为空,返回 -1 。Re原创 2021-04-26 19:28:54 · 253 阅读 · 0 评论 -
用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):实现 MyQueue 类:void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除并返回元素int peek() 返回队列开头的元素boolean empty() 如果队列为空,返回 true ;否则,返回 false...原创 2021-04-26 10:56:52 · 63 阅读 · 0 评论 -
用队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通队列的全部四种操作(push、top、pop 和 empty)。实现 MyStack 类:void push(int x) 将元素 x 压入栈顶。int pop() 移除并返回栈顶元素。int top() 返回栈顶元素。boolean empty() 如果栈是空的,返回 true ;否则,返回 false//思路://两个队列//入数据,往不为空的那个队列入//保持另一个队列为空//出数据,前size-1个倒空队列typ原创 2021-04-25 20:29:08 · 41 阅读 · 0 评论 -
队列的基本操作
实现队列用单链表构造队列的结构体typedef int QDataType;//定义结点typedef struct QueueNode{ struct QueueNode* next; //结点指针域 QDataType data; //结点数据}QueueNode;//定义队列 typedef struct Queue //若不用typedef,则后面函数定义变量必须使用struct Queue{ QueueNode* head; QueueNode* tail;原创 2021-04-25 16:53:49 · 86 阅读 · 0 评论 -
栈的基本操作
定义栈typedef int STDataType;struct Stack{ STDataType* a; //数组 int top; //栈顶 int capacity; //容量,方便增容};typedef struct Stack Stack;初始化栈void StackInit(Stack* pst){ assert(pst); //不方便增容 /*pst->a = NULL; pst->top = 0; pst->capac原创 2021-04-23 21:44:21 · 58 阅读 · 0 评论 -
顺序表与链表对比
顺序表优点:(1)按下标进行随机访问(2)CPU高速缓存命中效率比较高(访问数据时,在缓存,则命中,物理空间是连续的)注意:顺序表是连续缓存的,可以一次存储多个字节,连续访问,则直接命中;链表不是连续空间存储的,当访问完前一个空间,访问下一个数据时,又是重新新的地址。缺点:(1) 空间不够需要增容(一定程序的性能消耗)(2)头部或者中间插入删除数据,需要挪动数据,效率比较低链表优点:(1)按需申请内存,需要存一个数据,就申请一块内存,也不存在空间浪费(2)任意空间O(1)时间内插入原创 2021-04-21 19:35:24 · 53 阅读 · 0 评论 -
链表分割
现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。原创 2021-04-21 18:32:49 · 77 阅读 · 0 评论 -
合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。输入:l1 = [1,2,4], l2 = [1,3,4]输出:[1,1,2,3,4,4]原创 2021-04-21 18:29:04 · 58 阅读 · 0 评论 -
带头结点的双向链表的基本操作
定义双链表typedef int LTDataType;typedef struct ListNode{ struct ListNode* next; struct ListNode* prev; LTDataType data;}ListNode;创建结点ListNode* BuyListNode(LTDataType x){ ListNode* node = (ListNode*)malloc(sizeof(ListNode)); node->next = NULL;.原创 2021-04-20 20:59:09 · 416 阅读 · 0 评论 -
删除链表中重复的结点
题目:在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5利用三个指针:prev cur next还有极端情况:1 → 1→ 3 → 3 → 4 → 4此时的prev是为空的,可以设置一个头结点pHead来解决。 ListNode* deleteDuplication(ListNode* pHead) {原创 2021-04-19 10:45:49 · 39 阅读 · 0 评论 -
对链表进行插入排序
对链表进行插入排序。struct ListNode* insertionSortList(struct ListNode* head){ //链表为空或只有一个结点 if(head == NULL || head->next == NULL) return head; //1、循环的初始条件 struct ListNode* sortHead = head; struct ListNode* cur = head->next; /原创 2021-04-19 09:59:50 · 77 阅读 · 0 评论 -
复制带随机指针的链表
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。返回复制链表的头节点。用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:val:一个表示 Node.val 的整数。random_in原创 2021-04-19 08:46:55 · 82 阅读 · 0 评论 -
环形链表
环形链表Ⅰ题目:给定一个链表,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。如果链表中存在环,则返回 true 。 否则,返回 false 。思路:利用快慢指针,fast一次走两步,slow一次走一步,若是环,肯定会相遇bool hasC原创 2021-04-18 19:10:41 · 152 阅读 · 0 评论 -
链表的回文结构
思路一:开一个int a[900],链表的数据放到数组,判断数组思路二:先找到中间节点、后半部分逆置、再比较原创 2021-04-18 11:16:51 · 79 阅读 · 0 评论 -
相交链表
编写一个程序,找到两个单链表相交的起始节点。思路:1.判断是否相交2.相交求交点拿结点的地址相比,而不是值相比(判断尾指针是否相同)计算出两个链表的长度,让长的链表先走差距步 ,再同时走,第一个相同的结点,就是交点//1.判断是否相交 //2.相交求交点 //拿结点的地址相比,而不是值相比(判断尾指针是否相同) //计算出两个链表的长度,让长的链表先走差距步 //再同时走,第一个相同的结点,就是交点struct ListNode *getIntersectionNode(struct原创 2021-04-18 11:09:12 · 41 阅读 · 0 评论 -
单链表的基本操作
单链表的定义typedef int SLTDataType; //定义数据类型,若数据类型不是int,方便修改//定义结点指针typedef struct SListNode{ SLTDataType data; struct SListNode* next; //指针指向下一个结点,也是和自己同样的类型}SList;//建立新结点SLTNode* BuySLTNode(SLTDataType x){ SLTNode* node = (SLTNode*)malloc(siz原创 2021-04-15 08:57:53 · 69 阅读 · 0 评论 -
反转链表
反转一个单链表法一:利用3个指针struct ListNode* reverseList(struct ListNode* head){ if(head == NULL || head->next == NULL) return head; struct ListNode* n1 = NULL, *n2 = head, *n3 = head->next; while(n2) //直到n2为空结束循坏 { //翻转原创 2021-04-16 16:43:20 · 89 阅读 · 0 评论 -
快慢指针的算法
1.链表的中间结点题目:给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。当fast->next指向NULL时,结束循环,slow指针指向的结点为中间结点。当fast指向NULL时,结束循环,slow指针指向的结点为中间结点(结点数为偶数个时,返回中间两个数的第二个数)。//快慢指针,快指针一次走两步,慢指针一次走一步,遍历一次struct ListNode* middleNode(struct ListNode* head){原创 2021-04-14 21:35:33 · 231 阅读 · 0 评论