八大排序算法之堆排序的实现+经典TopK问题

目录

一.堆元素的上下调整接口

1.前言

2.堆元素向上调整算法接口

3.堆元素向下调整算法接口

二.堆排序的实现

1.空间复杂度为O(N)的堆排序(以排升序为例)

思路分析:

代码实现:

排序测试:

​时空复杂度分析:

2. 空间复杂度为O(1)的堆排序(以排降序为例)

将数组arr调整成堆的思路:

将数组arr调整成堆的时间复杂度分析: ​

在数组arr数组被调整成堆的基础上完成排序的思路

堆排序代码实现:

排序时空复杂度分析:

三.用堆数据结构解决TopK问题

1. 问题描述:

 2.问题分析与求解

 


一.堆元素的上下调整接口

1.前言

完全二叉树的物理结构和逻辑结构:

关于堆和堆元素上下调整算法接口设计原理分析参见青菜的博客http://t.csdn.cn/MKzyticon-default.png?t=N176http://t.csdn.cn/MKzyt青菜友情提示:想要深刻理解堆排序,必须掌握堆的构建

注意:接下来给出的两个接口针对小根堆元素调整算法接口,若需要用到大根堆数据结构,只需在小根堆的元素调整算法接口中子父结点值比较符号换一下方向即可用于实现大根堆.

2.堆元素向上调整算法接口

函数首部:

void AdjustUp(HPDataType* arry, size_t child)  //child表示孩子结点的编号

HPDataType是typedef定义的数据类型,arry是指向堆区数组的指针,child是待调整的结点在完全二叉树中的编号(物理上是其数组下标)

  •  算法调用场景: 

接口实现:

//元素交换接口
void Swap(HPDataType* e1, HPDataType* e2)
{assert(e1 && e2);HPDataType tem = *e1;*e1 = *e2;*e2 = tem;
}//小堆元素的向上调整接口
void AdjustUp(HPDataType* arry, size_t child)  //child表示待调整的结点的编号
{assert(arry);size_t parent = (child - 1) / 2;           //找到child结点的父结点while (child > 0)						   //child减小到0时则调整结束(说明待调整结点被调整到了根结点位置){if (arry[child] < arry[parent])        //父结点大于子结点,则子结点需要上调以保持小堆的结构{Swap(arry + child, arry+parent);child = parent;				//将原父结点作为新的子结点继续迭代过程parent = (child - 1) / 2;	//继续向上找另外一个父结点}else{break;						//父结点不大于子结点,则堆结构任然成立,无需调整}}
}
  • 循环的结束分两种情况:
  1. child减小到0时,说明待调整结点调整到了根结点的位置(小根堆数据结构恢复)
  2. 某次父子结点比较中,父结点的值若大于子结点,则说明小根堆数据结构恢复,break跳出循环即可
  • 调用该接口的前提是:待调整的结点上层结构(包括待调整结点的所在层,但不包括待调整结点本身)满足小根堆的数据结构,比如:否则的话堆元素的调整将失去意义(因为只有在满足上述前提的情况下,每次调用完该接口,待调整的结点的上层结构保持小根堆的数据结构,并且以待调整结点为叶结点的上层结构会成为一个堆)
  • 大根堆的元素向上调整算法接口:
  • 若要将接口改为大根堆元素向上调整算法接口,只需将上图中的红圈中的小于号改为大于号即可

3.堆元素向下调整算法接口

函数首部:

void AdjustDown(HPDataType* arry,size_t size,size_t parent)

HPDataType是typedef定义的数据类型,arry是指向堆区数组首地址的指针,size是堆的元素总个数,parent是待调整的结点在完全二叉树中的编号(物理上是其数组下标)

  •  算法调用场景: 

接口实现:

//元素交换接口
void Swap(HPDataType* e1, HPDataType* e2)
{assert(e1 && e2);HPDataType tem = *e1;*e1 = *e2;*e2 = tem;
}//小堆元素的向下调整接口
void AdjustDown(HPDataType* arry,size_t size,size_t parent)
{assert(arry);size_t child = 2 * parent + 1;   //确定父结点的左孩子的编号while (child < size)			 //child增加到大于或等于size时则调整结束{if (child + 1 < size && arry[child + 1] < arry[child]) //确定左右孩子中较小的孩子结点{++child;}if ( arry[child] < arry[parent])//父结点大于子结点,则子结点需要上调以保持小堆的结构{Swap(arry + parent, arry + child);parent = child;				//将原子结点作为新的父结点继续迭代过程child = 2 * parent + 1;		//继续向下找另外一个子结点}else{break;						//父结点不大于子结点,则堆结构任然成立,无需调整}}
}
  •  算法需要注意的一些边界条件:
  1. child >= size说明被调整元素已经被交换到了叶结点的位置,小根堆数据结构恢复,终止循环
  2. 接口中,我们只设计了一个child变量来表示当前父结点的孩子结点编号,因此我们需要先确定左右孩子中哪一个结点值较小,令child等于较小的孩子结点的编号:
    if (child + 1 < size && arry[child + 1] > arry[child]) //确定左右孩子中较小的孩子结点
    {++child;
    }

    child + 1<size判断语句是为了确定当前父结点的右孩子是否存在

  • 调用该接口的前提是:待调整的结点位置的左右子树都满足小根堆的数据结构,比如:否则的话堆元素的调整将失去意义(因为只有在满足上述前提的情况下,每次调用完该接口后,待调整的结点位置的左右子树保持小根堆的数据结构,并且以待调整结点为根结点的子树会成为一个堆)

  • 大根堆的元素向下调整算法接口:

  • 若要实现大根堆的元素向下调整算法接口,我们只需将上图红圈中的两个小于号改为大于号即可 

堆元素上下调整算法接口的实现原理分析参见:http://t.csdn.cn/MKzyticon-default.png?t=N176http://t.csdn.cn/MKzyt

二.堆排序的实现

有了堆元素的上下调整算法接口后,我们便可以利用堆的数据结构来实现高效的排序算法.

现在我们给出一个一百个元素的数组(每个元素随机附一个值):

typedef int HPDataType;
int main()
{int arr[100] = { 0 };srand((unsigned int)time(NULL));for (int i = 0; i < 100; i++){arr[i] = rand() % 10000;        //数组每个元素赋上一个随机值}return 0;
}

堆排序函数接口:

void HeapSort(int * arr,int size);

 arr是指向待排序数组首地址的指针,size是待排序的数组的元素个数

1.空间复杂度为O(N)的堆排序(以排升序为例)

思路分析:

  • 实现堆排序的其中一种非常暴力的思路是:
  1. 在HeapSort接口中动态开辟一个和待排序数组空间大小相同Heap数组作为
  2. 然后将待排序数组的元素逐个尾插到Heap数组中同时调用堆元素向上调整算法调整堆尾元素的位置来建堆(排升序则建立小根堆)
  3. 建堆过程完成后,再逐个取出堆顶数据(按照堆顶元素删除的方式取出,具体参见堆的实现http://t.csdn.cn/vhbJf)(堆顶数据为堆中的最小元素)从待排序数组首地址开始覆盖待排序数组的空间即可完成排序

排序算法图解:

  • 先将arr中的元素逐个尾插到Heap数组中建堆
  • 逐个Heap数组的堆顶元素利用堆顶元素删除操作放回到arr数组中,完成升序排序(其原理在于小根堆堆顶元素永远是堆中的最小元素)(堆顶元素删除操作指的是:先将堆顶元素与堆尾元素交换,维护堆尾的下标指针减一(堆元素个数减一),再将堆顶元素向下调整恢复小根堆数据结构):

代码实现:

//元素交换接口
void Swap(HPDataType* e1, HPDataType* e2)
{assert(e1 && e2);HPDataType tem = *e1;*e1 = *e2;*e2 = tem;
}//小堆元素的向上调整接口
void AdjustUp(HPDataType* arry, size_t child)  //child表示待调整的结点的编号
{assert(arry);size_t parent = (child - 1) / 2;           //找到child结点的父结点while (child > 0)						   //child减小到0时则调整结束(说明待调整结点被调整到了根结点位置){if (arry[child] < arry[parent])        //父结点大于子结点,则子结点需要上调以保持小堆的结构{Swap(arry + child, arry+parent);child = parent;				//将原父结点作为新的子结点继续迭代过程parent = (child - 1) / 2;	//继续向上找另外一个父结点}else{break;						//父结点不大于子结点,则堆结构任然成立,无需调整}}
}//小堆元素的向下调整接口
void AdjustDown(HPDataType* arry,size_t size,size_t parent)
{assert(arry);size_t child = 2 * parent + 1;   //确定父结点的左孩子的编号while (child < size)			 //child增加到大于或等于size时则调整结束{if (child + 1 < size && arry[child + 1] < arry[child]) //确定左右孩子中较小的孩子结点{++child;}if ( arry[child] < arry[parent])//父结点大于子结点,则子结点需要上调以保持小堆的结构{Swap(arry + parent, arry + child);parent = child;				//将原子结点作为新的父结点继续迭代过程child = 2 * parent + 1;		//继续向下找另外一个子结点}else{break;						//父结点不大于子结点,则堆结构任然成立,无需调整}}
}void HeapSort(int* arr, int size)
{assert(arr);int* Heap = (int*)malloc(size * sizeof(int));assert(Heap);int ptrarr = 0;		//维护arr数组的下标指针int ptrheap = 0;	//维护Heap数组的下标指针//逐个尾插元素建堆while (ptrarr < size){Heap[ptrheap] = arr[ptrarr]; //将arr数组中的元素逐个尾插到Heap数组中AdjustUp(Heap, ptrheap);     //每尾插一个元素就将该元素向上调整保持小堆的数据结构ptrheap++;ptrarr++;}//逐个将堆顶的元素放回arr数组(同时进行删堆操作)ptrarr = 0;int HeapSize = size;while (ptrarr < size){Swap(&Heap[0], &Heap[HeapSize - 1]);  //交换堆顶和堆尾的元素arr[ptrarr] = Heap[HeapSize-1];		  //将原堆顶元素插入arr数组中HeapSize--;                           //堆元素个数减一(完成堆数据弹出)ptrarr++;                             //维护arr的下标指针+1AdjustDown(Heap, HeapSize, 0);        //将交换到堆顶的数据向下调整恢复堆的数据结构}
}

排序测试:

int main()
{int arr[100] = { 0 };srand((unsigned int)time(NULL));for (int i = 0; i < 100; i++){arr[i] = rand() % 10000;        //数组每个元素赋上一个随机值}HeapSort(arr, 100);for (int i = 0; i < 100; ++i){printf("%d ", arr[i]);}return 0;
}

时空复杂度分析:

  • 由于尾插建堆堆顶删堆时间复杂度都是O(NlogN),因此排序的时间复杂度为O(NlogN)
  • 显然,在HeapSort接口中多开辟了一个Heap数组,排序的空间复杂度为O(N)
  • 关于建堆和删堆的时间复杂度证明参见青菜的博客:http://t.csdn.cn/MKzyticon-default.png?t=N176http://t.csdn.cn/MKzyt
  • 该种堆排序代码量很大,数据并发量也很大,而且空间复杂度较高,接下来我们来实现一种最优良的堆排序算法

2. 空间复杂度为O(1)的堆排序(以排降序为例)

前面的堆排序算法中引入了Heap数组来建堆,浪费了很多空间。

实际上,我们可以在待排序数组上原地完成堆的构建(即将数组arr调整成堆).

将数组arr调整成堆的思路:

  • 现有一个乱序数组arr,逻辑上我们将其看成一颗完全二叉树:
  • 接下来我们尝试用堆的元素向下调整算法接口将arr调整成小根堆 
  1. 调用堆元素向下调整接口的前提是:待调整的结点位置的左右子树都满足小根堆的数据结构(因为在满足这个前提的情况下,我们每次调用完该接口待调整的结点位置的左右子树保持小根堆的数据结构,并且以待调整结点为根结点的子树会成为一个堆)
  2. 由上述前提可知,如果从堆顶(或中间任意一个位置的结点)元素开始调整堆是没有意义的,所以我们只能从堆尾的子结构开始调堆:
  3. 通过上图的分析,我们可以通过堆尾元素找到第一个要被向下调整的结点,然后从第一个要被向下调整的结点开始依次往前向下调整其他结点直到完成对树的根结点的向下调整之后,整颗完全二叉树就会被调整成堆:
  4. 调堆小动画:
  • 实现将arr数组调整成小根堆的代码:
    void HeapSort(int* arr, int size)
    {assert(arr);int parent = (size - 1 - 1) / 2;	//找到第一个要被调整向下调整的元素for (; parent >= 0; --parent){AdjustDown(arr, size, parent);  //逐个元素向下调整完成堆的构建}
    }

将数组arr调整成堆的时间复杂度分析: 

因此假设arr数组中有N个元素,将数组arr调整成堆的时间复杂度为:O(N)

在数组arr数组被调整成堆的基础上完成排序的思路

  • 数组arr被调整成小根堆后,我们只需逐个删除堆顶元素就可以完成所有数的降序排序
  • 堆元素删除操作指的是:先将堆顶元素与堆尾元素交换,维护堆尾的下标指针减一(堆元素个数减一),再将堆顶元素向下调整恢复小根堆数据结构)
  • 逐个删除堆顶元素完成降序排序的过程图解:
  •  由上述算法设计思路可知:为了完成堆排序我们只需额外设计一个堆元素向下调整接口

堆排序代码实现:

//元素交换接口
void Swap(HPDataType* e1, HPDataType* e2)
{assert(e1 && e2);HPDataType tem = *e1;*e1 = *e2;*e2 = tem;
}//小堆元素的向下调整接口
void AdjustDown(HPDataType* arry,size_t size,size_t parent)
{assert(arry);size_t child = 2 * parent + 1;   //确定父结点的左孩子的编号while (child < size)			 //child增加到大于或等于size时则调整结束{if (child + 1 < size && arry[child + 1] < arry[child]) //确定左右孩子中较小的孩子结点{++child;}if ( arry[child] < arry[parent])//父结点大于子结点,则子结点需要上调以保持小堆的结构{Swap(arry + parent, arry + child);parent = child;				//将原子结点作为新的父结点继续迭代过程child = 2 * parent + 1;		//继续向下找另外一个子结点}else{break;						//父结点不大于子结点,则堆结构任然成立,无需调整}}
}void HeapSort(int* arr, int size)
{assert(arr);int parent = (size - 1 - 1) / 2;	//找到第一个要被调整向下调整的元素for (; parent >= 0; --parent){AdjustDown(arr, size, parent);  //逐个元素向下调整完成堆的构建}while (size > 0)					//逐个删除堆顶元素完成降序排序,我们将size作为堆尾指针{Swap(&arr[0], &arr[size - 1]);  //交换堆尾与堆顶元素size--;							//堆尾指针减一,堆元素个数减一AdjustDown(arr, size, 0);       //将堆顶元素向下调整恢复小根堆数据结构}
}

排序接口测试: 

int main()
{int arr[100] = { 0 };srand((unsigned int)time(NULL));for (int i = 0; i < 100; i++){arr[i] = rand() % 10000;      //数组每个元素赋上一个随机值}HeapSort(arr, 100);for (int i = 0; i < 100; ++i){printf("%d ", arr[i]);}return 0;
}

排序时空复杂度分析:

  • 逐个删除堆顶元素直到将堆删空的时间复杂度为O(NlogN),证明分析参见青菜的博客:http://t.csdn.cn/vhbJficon-default.png?t=N176http://t.csdn.cn/vhbJf
  • 已知将arr数组调整成堆的时间复杂度为O(N),因此堆排序整体的时间复杂度为O(NlogN)
  • 同时易知,堆排序算法的空间复杂度为O(1)
  • 可见堆排序是一个非常高效的排序算法(至少比冒泡厉害多了)

三.用堆数据结构解决TopK问题

TopK问题指的是,从N个元素数组中,选出K个最值.(K<=N)

Leetcode上面有相关题型.

面试题 17.14. 最小K个数 – 力扣(Leetcode) 

1. 问题描述:

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。(数组元素个数为arrSize)

(k<=arrSize)

示例:

输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]

题解接口: 

int* smallestK(int* arr, int arrSize, int k, int* returnSize)
{}

arrSize为题设数组的元素个数,k为要找出的最小数的个数,returnSize是结果数组元素个数

 2.问题分析与求解

  • 本题如果直接对arr数组进行排序理论上是可以解决的,但是时间效率略低(O(NlogN)),有种杀鸡用牛刀的感觉
  • 我们可以考虑利用堆数据结构实现本题的最优解之一:
  1. 首先创建一个k*sizeof(int)字节大小数组Heap用于存储堆
  2. 然后将arr中前k个元素尾插到Heap中建堆
  3. 然后将arr中后(arrSize-k)个元素逐个与Heap堆顶的元素比较,若arr中后(arrSize-k)个元素中的某元素小于Heap堆顶的元素,则将其与Heap堆顶元素交换,再将其进行向下调整保持堆的数据结构(元素交换入堆)
  4. 完成arr中后(arrSize-k)个元素Heap堆顶遍历比较后,堆中最后剩下的就是arr数组中最小的k个元素

算法图解: 

算法的合理性证明:

  • 由于大根堆堆顶元素是堆中的最大元素,因此在arr中后(arrSize-k)个元素Heap堆顶遍历比较的过程中没有入堆的元素一定都大于堆中的k个元素,因此最终堆中的k个元素一定是arr数组中最小的k个元素

题解代码:

void Swap(int* e1 ,int* e2)
{int tem = *e1;*e1 = *e2;*e2 = tem;
}//大堆元素的向上调整接口
void AdjustUp(int * arry, size_t child)     //child表示待调整结点的编号
{assert(arry);size_t parent = (child - 1) / 2;while (child > 0)						//child减小到0时则调整结束{if (arry[child] > arry[parent])     //父结点小于子结点,则子结点需要上调以保持大堆的结构{Swap(arry + child, arry+parent);child = parent;				    //将原父结点作为新的子结点继续迭代过程parent = (child - 1) / 2;	    //继续向上找另外一个父结点}else{break;						    //父结点不小于子结点,则堆结构任然成立,无需调整}}
}//大堆元素的向下调整接口
void AdjustDown(int * arry,size_t size,size_t parent)
{assert(arry);size_t child = 2 * parent + 1;   //确定父结点的左孩子的编号while (child < size)			 //child增加到大于或等于size时则调整结束{if (child + 1 < size && arry[child + 1] > arry[child]) //确定左右孩子中较大的孩子结点{++child;}if ( arry[child] > arry[parent])//父结点小于子结点,则子结点需要上调以保持大堆的结构{Swap(arry + parent, arry + child);parent = child;				//将原子结点作为新的父结点继续迭代过程child = 2 * parent + 1;		//继续向下找另外一个子结点}else{break;						//父结点不小于子结点,则堆结构任然成立,无需调整}}
}int* smallestK(int* arr, int arrSize, int k, int* returnSize)
{if(0==k){*returnSize =0;return NULL;}int * Heap = (int*)malloc(k*sizeof(int));*returnSize = k;                     //创建一个空间大小为k的数组用于存储堆int ptrHeap =0;                      //维护堆尾的指针while(ptrHeap<k)                     //将arr数组前k个元素尾插到Heap中完成建堆{Heap[ptrHeap]=arr[ptrHeap];AdjustUp(Heap,ptrHeap);    ptrHeap++;}int ptrarr = k;             //用于遍历arr中后(arrSize-k)个元素的下标指针while(ptrarr < arrSize)     //将arr中后(arrSize-k)个元素逐个与Heap堆顶的元素进行比较{//如果找到arr中后(arrSize-k)个元素中比堆顶元素小的元素则将该元素替换入堆//并通过堆元素向下调整接口保持大根堆的数据结构if(Heap[0]>arr[ptrarr]){Swap(&Heap[0],&arr[ptrarr]);AdjustDown(Heap,k,0);}ptrarr++;}return Heap;                  //返回Heap数组作为及结果
}

算法时空复杂度分析:

设数组arr元素个数为N

  • 建立Heap数组堆的时间复杂度为O(klogk)
  • arr后(N-k)个元素与heap堆顶元素比较并入堆的时间复杂度为O((N-k)logk)(在最坏的情况下,arr后(N-k)个元素每个都进行了交换入堆并且被调整到了堆的叶子结点位置)
  • 因此算法的总体时间复杂度为O(Nlogk)
  • 易知算法的空间复杂度为O(k)

TopK问题的求解思想有着十分重要的实际意义

比如在硬盘中有十亿个数据,我们想选出其中的100个最小值,那么利用上面的算法思想我们就可以在极少的内存消耗,极高的时间效率下完成这个工作.

 

 

 

 

 

 

查看全文

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.dgrt.cn/a/1537668.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章:

八大排序算法之堆排序的实现+经典TopK问题

目录
一.堆元素的上下调整接口
1.前言
2.堆元素向上调整算法接口
3.堆元素向下调整算法接口
二.堆排序的实现
1.空间复杂度为O(N)的堆排序(以排升序为例)
思路分析:
代码实现:
排序测试:
​时空复杂度分析:
2. 空间复杂度为O(1)的堆排序(以排降序为例)
将数组arr调……

[1.3_3]计算机系统概述——系统调用

文章目录第一章 计算机系统概述系统调用(一)什么是系统调用,有何作用(二)系统调用与库函数的区别(三)小例子:为什么系统调用是必须的(四)什么功能要用到系统调……

google面试的一个简单的白板编程题。

之前在CSDN的推文上看到了一篇关于google面试的面试题。题目考察的是白板编程。
给出的编程要求是:
/*[Tokyo,London,Rome,Donlon,Kyoto,Paris]*/
/* [Tokyo,Kyoto] [London,Donlon] [Rome] [Paris] */
/*一个城市名经过旋转后整个是另一个城市名&#xff0c……

PID简单的C++代码实现、代码很简短

PID算法精简的C代码实现对于PID控制的简洁明了的解释对于pid算法的c代码实现最后所运行的结果对于PID控制的简洁明了的解释
网上对于pid的介绍有很多了、这一篇帖子阅读量较大、讲解的也很简洁明了; 附上帖子的链接:一文读懂PID控制算法(抛弃……

关于增量式PID的代码(C语言)实现的详细说明–应该可以解决部分人的疑惑

关于增量式PID的代码(C语言)实现的详细说明
网上可以找到很多关于增量式PID的一些解释说明; 最终都可以得到如下的公式:
ΔuKp{e(n)-e(n-1)}Kie(n)Kd{e(n)-2e(n-1)e(n-2)} ;
最终转换成代码有很多是 typedef struct{float Kp; ……

容易理解的状态机、c++代码实现

何谓状态机
先附上百度上的一个解释: 举个最简单的例子。人有三个状态健康,感冒,康复中。触发的条件有淋雨(t1),吃药(t2),打针(t3),休……

最短路径寻优,Dijstra算法,附C++代码实现

最短路径寻优
(以下关于Dijstra的说明,是借用算法与数据结构的发帖说明、侵权即删) 原帖链接 最短路径寻优 如上图所示、如何寻求从 A 出发到 G 点的最短路径呢? Dijstra算法就是要求出这个最短的路径;
让我们来演示……

DSP283x系列,裸机程序移植到SYS/BIOS系统中操作流程、注意点、中断配置

DSP裸机程序以及SYS/BIOS操作系统
所谓裸机程序: 当我们在进行DSP开发的时候,比如在买开发板时所提供的一些例程。比如FLASH、ram配置GPIO使用, 各种总线中断的使用等等。一般提供的例程都差不多如下所示:
void main(void)
{Ini……

JAVA 中 protected 的一些个人理解

首先需要对 protected 进行溯源:
例如 class A {protected void fun(){}}class B extends A {}class main_l {public static void main(String[] args) {A a new A();B b new B();a.fun();b.fun();}}a.fun()和b.fun()的源头都是在 class A 当中;
……

如何用c语言实现类似C++中的成员函数

首先代码直接在下面贴好了;
实现的方法就是利用struct来构造一个结构体;除了正常的变量参数外,用函数指针代替其中的成员函数;
例如下面的结构体STUDENT,其中三个成员为函数指针;
我们在struct STUDENT ……

计算机笔试/面试常见逻辑题/智力题汇总

说明:按种类汇总,难度不分先后,做了分级罗列,方便后续扩充,大家有比较有意思的题目可以在讨论区讨论。 下面有的题题解相对复杂的直接参考了网上的一些解答,而有的题解我认为并不好的也做了补充&#xff0c……

OpenAI文档翻译——搭建第一个自己的ChatGPT应用

这篇主要是讲了重头到位创建一个基于OpenAI API的应用程序的过程,同时给出了Node.js、Python版本的实例代码。应用程序的构建总体来说是很简单的就是一个接口调用,前提是我们需要提供密匙。
如果想要获取更好的结果返回一个是可以给模型提供一些列子从而……

python以及PyCharm工具的环境安装与配置

这里以Windows为例
Python的安装
当然是到Python官网下载咯,https://www.python.org/downloads/点我直达,如图: 可以下载最新版本,可以下拉找到之前特定的版本安装,如图: 这里先择的是最新版的进行安装……

JavaScript【六】JavaScript中的字符串(String)

文章目录🌟前言🌟字符串(String)🌟单引号和双引号的区别🌟属性🌟 length :字符串的长度🌟 方法🌟 str.charAt(index);🌟 str.charCodeAt(index);🌟 String.fromCharCode(……

获取文件MD5小案例(未拆分文件)

文章目录前端获取MD5后端获取MD5前端获取MD5
1、引入js
<script src"js/spark-md5.min.js" type"text/javascript"></script>注:spark-md5库GitHub链接 2、这里是一个按钮和被隐藏调的<input/>标签 <body><button……

Java 进阶(15)线程安全集合

CopyOnWriteArrayList
线程安全的ArrayList,加强版读写分离。
写有锁,读⽆锁,读写之间不阻塞,优于读写锁。
写⼊时,先copy⼀个容器副本、再添加新元素,最后替换引⽤。
使⽤⽅式与ArrayList⽆异。
示例……

HR:面试官最爱问的linux问题,看看你能答对多少

文章目录摘要Linux的文件系统是什么样子的?如何访问和管理文件和目录?如何在Linux中查看和管理进程?如何使用Linux命令行工具来查看系统资源使用情况?如何配置Linux系统的网络设置?如何使用Linux的cron任务调度器来执行……

vscode开发常用的工具栏选项,查看源码技巧以及【vscode常用的快捷键】

一、开发常用的工具栏选项
1、当前打开的文件快速在左侧资源树中定位: 其实打开了当前的文件已经有在左侧资源树木定位了,只是颜色比较浅 2、打开太多文件的时候,可以关闭 3、设置查看当前类或文件的结构 OUTLINE
相当于idea 查看当前类或接……

数据要素化条件之一:原始性

随着技术的发展,计算机不仅成为人类处理信息的工具,而且逐渐地具有自主处理数据的能力,出现了替代人工的数据智能技术。数据智能的大规模使用需要关于同一分析对象或同一问题的、来源于不同数据源的海量数据。这种数据必须是针对特定对象的记……

【面试题 高逼格利用 类实现加法】编写代码, 实现多线程数组求和.

编写代码, 实现多线程数组求和.关键1. 数组的初始化关键2. 奇偶的相加import java.util.Random;public class Thread_2533 {public static void main(String[] args) throws InterruptedException {// 记录开始时间long start System.currentTimeMillis();// 1. 给定一个很长的……

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注