当前位置: 首页 > news >正文

长沙哪家公司做网站兴化市建设局网站

长沙哪家公司做网站,兴化市建设局网站,建站公司转型做什么业务,公司简介模板文字版目录 七大排序的时间复杂度和稳定性 排序 插入排序 简单插入排序 希尔排序 选择排序 简单选择排序 堆排序 交换排序 冒泡排序 快速排序 快排的递归实现 hoare版本的快排 挖坑法的快排 双指针法的快排 快排的非递归 归并排序 归并的递归实现 归并的非递归实现…

目录

七大排序的时间复杂度和稳定性

排序

插入排序

简单插入排序

希尔排序

选择排序

简单选择排序

堆排序

交换排序

冒泡排序

快速排序

快排的递归实现 

hoare版本的快排

 挖坑法的快排

双指针法的快排

快排的非递归

归并排序

归并的递归实现

归并的非递归实现

补充

快排的三路划分


七大排序的时间复杂度和稳定性

排序时间的复杂度和稳定性-CSDN博客关于七大排序的时间复杂度和稳定性的总结,帮助读者迅速掌握各各排序的优劣,在不同情况下如何选择。 https://blog.csdn.net/2401_87944878/article/details/145404375

排序

排序就是将一组数据按照递增或递减的方式将其排列。

排序包含两种;

内部排序:数据元素全部放在内存中的排序。

外部排序:数据太多不能同时放在内存中,根据排序的过程不能在内外存之间移动的排序。外部排序要对文件进行操作。

排序包含有四大实现:插入排序,选择排序,交换排序,归并排序。根据这四个实现又可以分支出一共7个排序思想:简单插入排序,希尔排序;选择排序,堆排序;冒泡排序,快速排序;归并排序。下面我们对这七种排序进行讲解。


插入排序

插入排序包含两种:简单插入排序,希尔排序。

简单插入排序

如图,简单插入怕排序就是遍历原数组,将每一个元素放在其指定位置。先拿出一个元素,向前找看,比它大的先后移,直到找到比它小的。

//简单插入排序
void InsertSort(int* a, int n)
{//插入排序,向前找到元素的指定位置for (int i = 1; i < n; i++){int end = i;int cur = a[end];while(end>0){if (a[end - 1] > cur){a[end] = a[end - 1];end--;}elsebreak;}a[end] = cur;}
}

希尔排序

 希尔排序实际上是对简单插入排序的一种优化。简单插入排序每次与其相邻的元素进行比较,而希尔排序是将一个数组分成多个组,将每个组进行简单插入排序,这样可以让大的数迅速到前面去,小的数迅速到后面去。

可以看到第一次gap是5时,将下标0和5比较,1和6比较,2和7比较....这样可以迅速将大的数移到前面去,将小的数移到后面去,这样就使的数组更加趋于有序的状态。

通过gap从大到小的变化,使得当gap较小的时候可以快速向前找到它的位置,更快的让每次循环break掉,让效率更快。

//希尔排序
void ShellSort(int* a, int n)
{//希尔排序与插入排序的区别在于,其先进行预排序int gap = n;while (gap > 1){gap /= 2;for (int i = 0; i < gap; i++){for (int m = i + gap; m < n; m += gap){int end = m;int cur = a[end];while (end > 0){if (a[end - 1] > cur){a[end] = a[end - 1];end--;}elsebreak;}a[end] = cur;}}}
}

选择排序

选择排序包含两种简单选择排序和堆排序;

简单选择排序

简单选择排序就是遍历原数组,直接找到最大值或最小值将其放在尾和首,可以一次只找出一个最值,也可以将最大值和最小值同时找到。

以上是遍历未排序的数组每次找出最下的元素交换,下面演示遍历未排序的数组每次找打最小和最大的元素。 

//交换函数
void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}//简单选择排序
void SelectSort(int* a, int n)
{//一次遍历,选出最大值和最小值int left = 0;int right = n - 1;while (left < right){int min = left;int max = left;for (int i = left; i <= right; i++){if (a[min] > a[i])min = i;if (a[max] < a[i])max = i;}//交换Swap(&a[left], &a[min]);//注意此处,如果left对应的值就是最大值的时候,//将min和left交换后,max就在min的位置了if (left == max)Swap(&a[right], &a[min]);elseSwap(&a[right], &a[max]);left++, right--;}
}

堆排序

堆排序就是利用二叉树的性质,通过建大堆或小堆,将最大的数据或最小的数据放在指定位置。在二叉树中已经详细讲过堆了,这里就直接贴代码。

二叉树(C语言)-CSDN博客文章浏览阅读1.3k次,点赞19次,收藏18次。帮助读者快速掌握树这一数据结构,了解堆的功能,能够实现堆排序,以及如何再大量数据中快速找到前K个最大元素,如何处理普通二叉树,普通二叉树的遍历等知识。https://blog.csdn.net/2401_87944878/article/details/145262931https://blog.csdn.net/2401_87944878/article/details/145262931https://blog.csdn.net/2401_87944878/article/details/145262931https://blog.csdn.net/2401_87944878/article/details/145262931https://blog.csdn.net/2401_87944878/article/details/145262931https://blog.csdn.net/2401_87944878/article/details/145262931

//向下调整
void AdjustDown(int* a, int n, int parent)
{int child = 2 * parent + 1;while (child < n){if (child+1<n&&a[child] < a[child + 1])child++;if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = 2 * parent + 1;}elsebreak;}
}//堆排序
void HeapSort(int* a, int n)
{//先建大堆for (int i = (n - 2) / 2; i >= 0; i--){//向下调整AdjustDown(a, n, i);}//将堆顶的最大值和堆低交换int sz = n - 1;Swap(&a[0], &a[sz]);sz--;while (sz > 0){AdjustDown(a, sz + 1, 0);Swap(&a[0], &a[sz]);sz--;}
}

交换排序

交换排序分为冒泡排序和快速排序。

冒泡排序

冒泡排序简单,没有实际作用,这里直接贴代码。

//冒泡排序
void BubbleSort(int* a, int n)
{for (int i = 0; i < n - 1; i++){for (int m = 0; m < n - 1 - i; m++){if (a[m] > a[m + 1])Swap(&a[m], &a[m + 1]);}}
}

快速排序

快速排序是将一个元素key作为基准,先找到这个key的准确位置,将小于key的放在key的左边,将大于key的放在右边。

快排的递归实现 

hoare版本的快排

 如图:将数组首元素作为key,通过左右指针,让R指针先走找到小于key的值停,L指针再走大于key的时候停,将L位置和R位置交换,直到L和R相遇时停止,这个位置就是key排序后的位置。

思考:为什么要让R指针想走?能否让L指针想走? 

关于key的选择有三种方法:选择最左边的,随机选择,比较数组左右中间这三个值,选出次小的值。此处选择三数取中最好,可以尽量避免只出现一个递归函数。

//快排:Hoare版本
void QuickSort(int* a, int begin,int end)
{if (begin >= end)return;//快排就是将key放在正确位置上去。//三数取中int mid = Mid(begin, end);Swap(&a[begin], &a[mid]);int keyi = begin;int left = begin;int right = end;while (left < right){while (left < right && a[right] >= a[keyi])right--;while (left < right && a[left] <= a[keyi])left++;Swap(&a[left], &a[right]);}Swap(&a[keyi], &a[left]);keyi = left;QuickSort(a, begin, keyi - 1);QuickSort(a, keyi+1, end);
}
 挖坑法的快排

利用挖坑法可以直接不用思考数组那一边的指针先走的问题。

挖坑法就是将keyi的位置值保留,R指针找比key小的将其填在keyi的位置,R指针处变为坑,直到L指针和R指针相遇,将其位置的key填入坑。

//快排:挖坑法
void HoleSort(int* a, int begin, int end)
{if (begin >= end)return;int mid = Mid(begin, end);Swap(&a[mid], &a[begin]);int hole = begin;int left = begin;int right = end;int key = a[hole];while (left < right){while (left < right && a[right] >= key)right--;a[hole] = a[right];hole = right;while (left < right && a[left] <= key)left++;a[hole] = a[left];hole = left;}a[hole] = key;int keyi = hole;HoleSort(a, 0, keyi - 1);HoleSort(a, keyi+1, end);
}
双指针法的快排

分别利用两个指针,一个向前面走如果cur对用的值比key小就交换,两个指针都向前移动;如果cur对应的值大就不交换,cur向前移动。

//快排:双指针法
void DPoint(int* a, int begin, int end)
{if (begin >= end)return;int mid = Mid(begin, end);Swap(&a[begin], &a[mid]);int keyi = begin;int cur = begin;int pre = begin;while (cur <= end){if (a[cur] <= a[keyi]){if (cur != pre)Swap(&a[cur], &a[pre]);cur++;pre++;}else{cur++;}}Swap(&a[keyi], &a[pre - 1]);keyi = pre - 1;DPoint(a, begin, keyi - 1);DPoint(a, keyi+1, end);
}

快排的非递归

快排的非递归就是利用栈将其begin和end的值储存起来,再利用栈的“后入先出”的性质,每一次拿出一个范围再放入子范围,直到栈的空间为空时停止。

此处以Hoare的非递归为例。

typedef struct Stack
{int* a;int size;int capacity;
}Stack;//栈的初始化
void StackInit(Stack* sp)
{sp->capacity = 4;sp->a = (int*)malloc(sizeof(int) * (sp->capacity));if (sp->a == NULL)perror("malloc failed");sp->size = 0;
}//入栈
void StackPush(Stack* sp, int x)
{//检查空间够不够if (sp->size == sp->capacity){sp->capacity *= 2;int* tmp = (int*)realloc(sp->a, sizeof(int) * (sp->capacity));if (tmp == NULL)perror("realloc failed");sp->a = tmp;}sp->a[sp->size] = x;sp->size++;
}//出栈
void StackPop(Stack* sp)
{sp->size--;
}//返回栈顶元素
int StackTop(Stack* sp)
{return sp->a[sp->size - 1];
}//检查栈空间是否为空
bool IsStackEmpty(Stack* sp)
{if (sp->size == 0)return true;elsereturn false;
}
//快排:非递归
void QuickNon(int* a, int begin, int end)
{//快排的非递归就是将快排的左右间距存储在栈中Stack s;StackInit(&s);StackPush(&s, end);StackPush(&s, begin);while (!IsStackEmpty(&s)){int begin = StackTop(&s);StackPop(&s);int end = StackTop(&s);StackPop(&s);int left = begin;int keyi = left;int right = end;while (left < right){while (left < right && a[right] >= a[keyi])right--;while (left < right && a[left] <= a[keyi])left++;Swap(&a[left], &a[right]);}Swap(&a[left], &a[keyi]);keyi = left;if (begin < keyi - 1){StackPush(&s, keyi - 1);StackPush(&s, begin);}if (keyi + 1 < end){StackPush(&s, end);StackPush(&s, keyi + 1);}}
}


归并排序

归并排序的实现就是:先对小范围排序,再对大范围排序。如图:相对两个元素进行排序,再对4个元素进行排序,依次依次*2向后排序。

归并的递归实现

//归并排序
void Merge(int* a, int begin, int end)
{if (begin >= end)return;int mid = (begin + end) / 2;Merge(a, begin, mid);Merge(a, mid + 1, end);int begin1 = begin;int end1 = mid;int begin2 = mid + 1;int end2 = end;int* tmp = (int*)malloc(sizeof(int) * (end - begin + 1));int j = 0;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[j++] = a[begin1++];}elsetmp[j++] = a[begin2++];}while (begin1 <= end1)tmp[j++] = a[begin1++];while (begin2 <= end2)tmp[j++] = a[begin2++];memcpy(a + begin, tmp, sizeof(int) * (end - begin + 1));free(tmp);
}

归并的非递归实现

归并的非递归实现就不能用栈来存储18首尾的范围了,可以直接从2个元素排序开始,依次*2直到排完为止。

//归并的非递归实现
void MergeNon(int* a, int begin, int end)
{int gap = 1;while (gap < end){for (int i = 0; i <= end; i += 2 * gap){int begin1 = i;int end1 = i + gap - 1;int begin2 = i + gap;int end2 = i + 2 * gap - 1;if (begin2 > end){break;}if (end2 > end)end2 = end;int* tmp = (int*)malloc(sizeof(int) * (end2 - begin1 + 1));int j = 0;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2])tmp[j++] = a[begin1++];elsetmp[j++] = a[begin2++];}while (begin1 <= end1)tmp[j++] = a[begin1++];while (begin2 <= end2)tmp[j++] = a[begin2++];memcpy(a + i, tmp, sizeof(int) * (end2-i+1));free(tmp);}gap *= 2;}
}

补充

关于快排,当有大量重复的数据出现的时候,快排的key的位置可能就是最左边,导致向下递归后还是只有一组,当大量出现这种情况的时候就会导致快排变成简单选择排序,时间复杂度大大增加,导致效率降低。此处可以采用三路划分的快排解决。

快排的三路划分

三路划分与普通快排的区别:普通快排将数组分成两个部分,大于key和小于key的;而三路划分将快排分成三个部分,大于key,小于key和等于key的。

分为左右两个指针以及一个遍历数组的指针,将大于key的调到右边,将小于key的调到左边,将等于key的放在中间。

//快排的三路划分
void TQuickSort(int* a, int begin, int end)
{if (begin >= end)return;int mid = Mid(begin, end);Swap(&a[begin], &a[mid]);int keyi = begin;int key = a[begin];int left = begin;int cur = begin;int right = end;while (cur <= right){if (a[cur] < key){if (cur != left)Swap(&a[left], &a[cur]);left++, cur++;}else if (a[cur] > key){Swap(&a[cur], &a[right]);right--;}elsecur++;}keyi = left;TQuickSort(a, begin, keyi - 1);TQuickSort(a, keyi + 1, end);
}

http://www.yayakq.cn/news/602607/

相关文章:

  • 网站的seo如何优化谷歌网站统计
  • 专业网站建设人工智能深互动平台怎么使用
  • 微信端微网站怎么做公司网站建设会计分录
  • 网站备案完毕 怎样建设网站做网站的详细流程
  • 中达建设网站西安工商注册网上平台
  • 全屏家居网站模板做现货值得关注的财经网站
  • wordpress 移动端网页上海百度推广优化公司
  • 建设信息港网站水印wordpress
  • 手机端网站设计尺寸网站网络推广优化
  • 欧洲网站服务器微信导航网站怎么做
  • 深圳公司网站制作wordpress腾讯云储存
  • 电商网站设计的原则腾讯视频创作平台
  • 如何获得网站域名上海网站建设网页设计
  • 找人给公司做网站去哪找怎么做网站推广实际效果好
  • dw如何做网站登陆验证域名大全
  • 网站建设工作整改报告成都网页开发
  • 新手建站素材域名后有个wordpress
  • 网站开发技术文档格式零基础网页设计制作培训
  • 做网站的是哪类公司十大免费文案网站
  • 专门做优惠劵的网站做牛仔裤的视频网站
  • 网站导航作用东莞网站建设设计
  • 网站定制建设公司阿里云建设网站流程
  • 可信网站认证图标手机网站建设 上海
  • 婚庆摄影网站模板公众号开发平台官网
  • 织梦网站添加广告位百度号码认证
  • 建站系统是什么做网站包括什么
  • 图书管理系统网站开发深圳 建网站
  • 如何自己制作自己的网站门户网站自查报告
  • 网站编辑工作内容wordpress 快速编辑器
  • ip下的网站吗如何只做网站