类别 | 方法 | 数组实现 | 链表实现 | 稳定 | 适用场景 | ||
时间复杂度 | 空间复杂度 | 时间复杂度 | 空间复杂度 | ||||
插入排序 | 直接插入 | |
在数列近乎可下降到O(n) | ||||
shell排序 | - | - | 延续了上一思想 | ||||
交换排序 | 冒泡排序 | ||||||
快速排序 | 非递归: 递归: |
不考虑递归: |
改进: 1)小partition上:插入排序 2)重复元素多:头尾指针 or 三路快排 |
||||
选择排序 | 直接选择 | ||||||
堆排序 | - | - | |||||
归并排序 | |||||||
桶排序 | ? |
一个细节:在做partition时,为什么要从头尾两个方向向中间进行粗排序?
使得分割的左右两部分元素数量更均衡。只有一个方向遍历的话,等于key的元素分布会堆积在同一边;两个方向遍历的话,判断里都覆盖(或都不覆盖)等于key的元素,就能避免堆积。
(可直接运行)
编程心得:两个指针实际含义是 一个指向坑位,一个找新坑位。
#include <iostream>
using namespace std;
void print(int nums[], int l, int r){
for(int i=l; i<=r; ++i){
cout<<nums[i]<<" ";
}
cout<<endl;
}
void sort(int nums[], int l, int r){
if(l>=r) return;
int key = nums[l];
int il = l, ir = r;
while (il<ir) {
while(il<ir && nums[ir]>=key){
--ir;
}
if(il<ir) nums[il++] = nums[ir];
while(il<ir && nums[il]<=key){
++il;
}
if(il<ir) nums[ir--] = nums[il];
}
nums[il] = key;
sort(nums, l, il-1);
sort(nums, il+1, r);
}
int main(int argc, const char * argv[]) {
int nums[] = {2,4,1,3,2};
print(nums,0,4);
sort(nums, 0, 4);
print(nums,0,4);
return 0;
}
点1:链表中元素无法直接访问,导致找坑不能跳着找,因此解决办法是从前向后捋,记录前小后大的分界线,把未排序中小的往分界线放。
点2:key元素的坑位最后决定,但由于链表中无法直接访问,key一旦换开就很难找到,因此排序时先不要占用key的坑位,只在最后把头部的key和分界线上小的元素位置交换。
变量含义:p用来记录分界线上小于一边的元素,q用来找未排序中需要往前调动的小于的元素。
运行结果:实现一速度和内存略少于实现二。
实现一:链表不动,子链用首尾元素来判别。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
if(head==NULL || head->next==NULL) return head;
sort(head, NULL);
return head;
}
void sort(ListNode* head, ListNode* end){
if(head==end || head->next == end) return;
int key = head->val;
ListNode *p = head, *q = head->next;
bool isok = true;
while(q!=end){
if(q->val < key){
p = p->next;
swap(p->val, q->val);
}
q = q->next;
}
swap(p->val, head->val);
sort(head, p);
sort(p->next, end);
}
void swap(int &p, int &q){
int tmp = q;
q = p;
p = tmp;
}
};
实现二:断开链表,子链是拆成单独的链。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
if(head==NULL || head->next==NULL) return head;
ListNode *tmp = head->next;
ListNode *less = new ListNode(0);
ListNode *big = new ListNode(0);
ListNode *i = big, *j = less;
while(tmp!=NULL){
if(tmp->val >= head->val){
i->next = tmp;
i = i->next;
}else{
j->next = tmp;
j = j->next;
}
tmp = tmp->next;
}
i->next = NULL;
j->next = NULL;
ListNode *left = sortList(less->next);
ListNode *right = sortList(big->next);
if(left!=NULL){
i = left;
while(i->next!=NULL){
i = i->next;
}
i->next = head;
}
head->next = right;
return (left)?left:head;
}
};
自顶向下:不断二分,逐个合并有序子列。
(代码可直接运行)
#include <iostream>
using namespace std;
void print(int nums[], int len){
for(int i=0; i<len; ++i){
cout<<nums[i]<<" ";
}
cout<<endl;
}
void merge(int nums[], int l, int mid, int r){
int tmp[r-l+1];
int itmp = 0, ir = mid+1, il = l;
while(il<=mid && ir<=r){
if(nums[il]<=nums[ir]){
tmp[itmp] = nums[il++];
}else{
tmp[itmp] = nums[ir++];
}
++itmp;
}
while(il<=mid){
tmp[itmp++] = nums[il++];
}
while(ir<=r){
tmp[itmp++] = nums[ir++];
}
itmp = 0;
il = l;
while(itmp<r-l+1){
nums[il++] = tmp[itmp++];
}
print(nums,4);
}
void sort(int nums[], int l, int r){
if(l>=r) return;
int mid = (l + r) / 2;
sort(nums, l, mid);
sort(nums, mid+1, r);
merge(nums, l, mid, r);
}
int main(int argc, const char * argv[]) {
int nums[] = {4,2,1,3};
sort(nums, 0, 3);
print(nums, 4);
return 0;
}
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
if(head==NULL || head->next==NULL) return head;
ListNode *t1 = head, *t2 = head;
while(t2!=NULL && t2->next != NULL){
t2 = t2->next->next;
if(t2==NULL) break;
t1 = t1->next;
}
t2 = t1->next;
t1->next = NULL;
ListNode* l1 = sortList(head);
ListNode* l2 = sortList(t2);
return merge(l1, l2);
}
ListNode* merge(ListNode* l1, ListNode* l2){
if(l1==NULL) return l2;
if(l2==NULL) return l1;
ListNode* node = new ListNode(0);
ListNode *tail = node;
while(l1!=NULL && l2!=NULL){
if(l1->val <= l2->val){
tail->next = l1;
l1 = l1->next;
}else{
tail->next = l2;
l2 = l2->next;
}
tail = tail->next;
tail->next = NULL;
}
if(l1!=NULL){
tail->next = l1;
}
if(l2!=NULL){
tail->next = l2;
}
return node->next;
}
};
参考:
1.数组实现的排序算法对比:https://blog.csdn.net/yushiyi6453/article/details/76407640
这里写目录标题一级目录二级目录三级目录第一章:计算机系统概述1:选择题第二章:数据在计算机中的表示一.选择题二.填空题三.判断题四.计算题一级目录二级目录三级目录第一章:计算机系统概述1:选择题微型计算机的发展以( )技术为标志。A、操作系统B、微处理器C、磁盘D、软件正确答案: B下列选项中,不属于计算机系统软件的是( )。A、操作系统B、服务程序C、语言处理程序D、自动控制程序正确答案: D冯·诺依曼机工作方式具有以下哪个特点( )?A、多指令流单数据流B、按地址
在第一篇中,我们使用了Handler,但是Handler处理任务的进程和Activity都是在主线程中,这样我们还是无法实现把任务交给他们现成处理的目标,因为主线程处理耗时操作最多只有5秒,否则会引发ANR错误。在Java中,我们使用多现成来处理任务,在Android中,我们如何来使用多现成处理呢。其实也是很简单的。1.MainActivityimport com.example.hand
本文主要是总结一下使用AXI-FULL调试的过程。 首先想到的是用RAM IP核来测试,方法是通过AXI接口向RAM写入一组数据并读出,看起来很简单,然而试了好久都没能出结果。如下图所示,其实AXI RAM就是在本地RAM接口的基础上套了一个AXI的壳 在使用modelsim仿真的时候总是会抛出一个警告,具体的警告类型忘了,下次有机会再尝试。试了好多次都
-Xms 为jvm启动时分配的初始堆的大小,也是堆大小的最小值,比如-Xms200m,表示分配200M-Xmx 为jvm运行过程中分配的最大堆内存,比如-Xmx500m,表示jvm进程最多只能够占用500M内存-Xss 为jvm启动的每个线程分配的内存大小,默认JDK1.4中是256K,JDK1.5+中是1M...
学会使用Z球,Z球在zbrush中是一个很好用的快速粗模的搭建工具,我们可以用来非常方便的创建一些基本形状出来,再进行细分或是雕刻就非常方便了。1.首先找到Z球的位置如图所示:2.在视图中拖出一个来,并进入编辑模式。3.直接拖拽就可以在第一个Z球上再增加一个新的Z球4.按A键可以直接预览到Z球变成网格之后的形状,再按一次A就可以回...
文章目录描述错误原因修改后参考描述错误在将Unity5.5.0版本的项目转换成Unity2018.1.1的项目时,一个玻璃的shader报错了。错误信息:Shader error in ‘Shader Forge/Examples/Refraction’: syntax error: unexpected token ‘;’ at line 261 (on d3d11)根据上面的报错信息,我们定位错误位置:错误代码:float attenuation = LIGHT_ATTEN
一、系统的启动过程如下。1、上电后,首先进行硬件启动,当硬件检测无误后,管理终端上出现下列信息:WelcometouseZTEeCarrier!!Copyright(c)2004-2006,ZTECo.,Ltd.SystemBooting......CPU:S3C45010ARM7TDMIBSPversion:1.2/0C...
问:f=@(x)acos(x)表示什么意思?其中@代表什么?今天杰哥给大家介绍一下函数句柄的详细知识。首先我们先看一个问题:表示什么意思呢?其中的@代表什么呢?我们来揭晓一下答案:f是函数句柄;@是定义句柄的运算符;相当于建立了一个函数文件:% 建立函数文件f.mfunctiony=f(x)y=cos(x);再给大家举个例子:则相当于建立了一个函数文件:%建立xsqual函数function y=xsqual(x)y=x^2+2*x+1;我们再做一个详细说明:.
GPHybrid ExampleTo run the example project, clone the repo, and run pod install from the Example directory first.Introduction前言Hybrid框架主要以JS+Native两者相互调用为主,从开发层面实现"一次开发,多处运行"的机制,成为真正适合跨平台的开发。 目前
1.android.permission.WRITE_USER_DICTIONARY 允许应用程序向用户词典中写入新词2.android.permission.WRITE_SYNC_SETTINGS 写入Google在线同步设置3.android.permission.WRITE_SOCIAL_STREAM 读取用户的社交信息流4.android.permission.WRITE_S...
elementui表单置空resetFields无效解决方法