冒泡排序,选择排序,插入排序,快速排序
2018-03-03 17:28
441 查看
一:冒泡排序
冒泡排序算法的运作如下:(从后往前)比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
冒泡排序总的平均时间复杂度为
。
相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。template<typename T>
//整数或浮点数皆可使用
void bubble_sort(T arr[], int len)
{
int i, j; T temp;
for (i = 0; i < len- 1; i++)
for (j = 0; j < len- 1 - i; j++)
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
链表的冒泡排序
基本思想:
对当前还未排好序的范围内的全部节点,自上而下对相邻的两个节点依次进行比较和调整,让键值(就是用它排 序的字段,我们取学号num为键值)较大的节点往下沉,键值较小的往上冒。即:每当两相邻的节点比较后发现它们的排序与排序要求相反时,就将它们互换。
1、排序后q节点指向p节点,在调整指向之前,我们要保存原p的指向节点地址,即:p2=p1->next->next;
2、顺着这一步一步往下推,排序后图16中p1->next->next要指的是p2->next,所以p1->next->next=p2->next;
3、在图15中p2->next原是q发出来的指向,排序后图16中q的指向要变为指向p的,而原来p1->next是指向p的,所以p2->next=p1->next;
4、在图15中p1->next原是指向p的,排序后图16中p1->next要指向q,原来p1->next->next(即p2)是指向q的,所以p1->next=p2;
5、至此,我们完成了相邻两节点的顺序交换。
6、下面的程序描述改进了一点就是记录了每次最后一次节点下沉的位置,这样我们不必每次都从头到尾的扫描,只需要扫描到记录点为止。 因为后面的都已经是排好序的了。
/*
==========================
功能:冒泡排序(由小到大)
返回:指向链表表头的指针
==========================
*/
struct student *BubbleSort (struct student *head)
{
struct student *endpt; //控制循环比较
struct student *p; //临时指针变量
struct student *p1,*p2;
p1 = (struct student *) malloc (LEN);
p1->next = head; //注意理解:我们增加一个节点,放在第一个节点的前面,主要是为了便于比较。因为第一个节点没有前驱,我们不能交换地址
head = p1; //让head指向p1节点,排序完成后,我们再把p1节点释放掉
for (endpt = NULL; endpt != head; endpt = p) //每次把最终节点记录为已经排序好的链表的首节点
{
for (p = p1 = head; p1->next->next != endpt; p1 = p1->next)
{
if (p1->next->num > p1->next->next->num) //如果前面的节点键值比后面节点的键值大,则交换
{
p2 = p1->next->next; //结合第1点理解
p1->next->next = p2->next; //结合第2点理解
p2->next = p1->next; //结合第3点理解
p1->next = p2; //结合第4点理解
p = p1->next->next; //每一次内for循环结束后p记录从此节点往后都是已经排序号的节点
}
}
}
p1 = head; //把p1的信息去掉
head = head->next; //让head指向排序后的第一个节点
free (p1); //释放p1
p1 = NULL; //p1置为NULL,保证不产生“野指针”,即地址不确定的指针变量
return head;
} 二:选择排序
选择排序的时间复杂度为 O(n)
选择排序是一个不稳定的排序,因为其中相同的元素在排列后的相对顺序可能发生改变
链表的选择排序struct student *checksort(struct stuent *head)
{
struct student *first;//新链表的首指针
struct student *tail;//新链表的尾指针
struct student *p;//当前正在比较的节点指针
struct student *p_min;//最小节点的前驱指针
struct student *min;//最小节点的指针
first=NULL;
while(head!=NULL)
{
for(p=head,min=head;p->next!=NULL;p=p->next)
{
if(p->next->num<min->num)
{
p_min=p;//最小节点的前驱节点指针
min=p->next;//最小节点的节点指针
}
}
}
if(first==NULL)//当排列后的有序链表还是一个空链表时
{
first=min;
tail=min;
}
else{
tail->next=min;
tail=tail->next;
}
//从原先链表中去除最小节点
if(min==head)
{
head=head->next;
}
else{
p_min->next=min->next;
}
if(first!=NULL)
tail->next=NULL;
head=first;
return head;
}直接选择排序
简单选择排序的基本思想:第1趟,在待排序记录r[1]~r
中选出最小的记录,将它与r[1]交换;第2趟,在待排序记录r[2]~r
中选出最小的记录,将它与r[2]交换;以此类推,第i趟在待排序记录r[i]~r
中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完
template<typename T>
void bubblersort( T arr[],int n)
{
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
if(arr[i]>arr[j])
{
T c=arr[j];
arr[j]=arr[i];
arr[i]=c;
}
}三.插入排序
插入排序的基本思想是:每步将一个待排序的记录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
链表的插入算法:struct student * InsertSort(struct student * head)
{
struct student * t;//待插入的节点指针
struct student * first;//剩余的带插入链表节点的首指针
struct student * p,*q;
first=head->next;;
head->next=NULL;
while((first!=NULL)
{
for(t=first,q=head;(q->next!=NULL)&&(q->num>t->num);p=q,q=q->next);//当退出循环时就把t插入到p节点之后q节点之前
first=first->next;//无需链表中的首节点离开插入到有序链表中
if(q==head)//插入到头结点处
head=t;
else
p->next=t;
t->next=q;
}
return head;
}直接插入排序:
直接插入排序的算法思路:(1) 设置监视哨temp,将待插入记录的值赋值给temp;(2) 设置开始查找的位置j;(3) 在数组中进行搜索,搜索中将第j个记录后移,直至temp.key≥r[j].key为止;(4) 将temp插入r[j+1]的位置上
也可以写为voidinsert_sort(int*array,unsignedintn)
{
inti,j;
int temp;
for(i=1;i<n;i++)
{
temp=*(array+i);
for(j=i;j>0&&*(array+j-1)>temp;j--)
{
*(array+j)=*(array+j-1);
}
*(array+j)=temp;
}
}
四:快速排序
快速排序是对冒泡排序的一种改进通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序为不稳定的排序
输入:
i=0,j=5.key=6要把所有比key小的数移到key的左边,所有比key大的数移到key的右边。先从尾端开始j递减比较,如果A[j]<key,那么A[j]和key互换,换过一次之后再从左端找第一个比key大的数移到右端第一次换后i=0,j=3,key=6
第二次换后
i=2,j=3,key=6
上边两次比较为一个循环,当i和j相遇后循环结束上边i和j一次循环后就相遇void Qsort(int a[],int low,int high)//low表示第一个元素的下边,high表示最后一个元素的下标
{
if(low>=high)
return ;
//把first和last初始化为首尾元素的下标
int first=low;
int last=high;
int key=a[first];
while(first<last)//当首尾元素相遇时循环结束
{
while(first<last&&a[last]>=key)
{
--last;
}
a[first]=a[last]
while(first<last&&a[first]<=key)
{
++first;
}
a[last]=a[first]
}
a[first]=key;
/*循环结束后可以保证比key小的值都在左边,大的都在右边,此时last指向第一个比key大的值的下标,first为key值的下标,需要对两边在此 行排序*/
Qsort(a,low,last-1);
Qsort(a,first+1,high);
}
冒泡排序算法的运作如下:(从后往前)比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
冒泡排序总的平均时间复杂度为
。
相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。template<typename T>
//整数或浮点数皆可使用
void bubble_sort(T arr[], int len)
{
int i, j; T temp;
for (i = 0; i < len- 1; i++)
for (j = 0; j < len- 1 - i; j++)
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
链表的冒泡排序
基本思想:
对当前还未排好序的范围内的全部节点,自上而下对相邻的两个节点依次进行比较和调整,让键值(就是用它排 序的字段,我们取学号num为键值)较大的节点往下沉,键值较小的往上冒。即:每当两相邻的节点比较后发现它们的排序与排序要求相反时,就将它们互换。
1、排序后q节点指向p节点,在调整指向之前,我们要保存原p的指向节点地址,即:p2=p1->next->next;
2、顺着这一步一步往下推,排序后图16中p1->next->next要指的是p2->next,所以p1->next->next=p2->next;
3、在图15中p2->next原是q发出来的指向,排序后图16中q的指向要变为指向p的,而原来p1->next是指向p的,所以p2->next=p1->next;
4、在图15中p1->next原是指向p的,排序后图16中p1->next要指向q,原来p1->next->next(即p2)是指向q的,所以p1->next=p2;
5、至此,我们完成了相邻两节点的顺序交换。
6、下面的程序描述改进了一点就是记录了每次最后一次节点下沉的位置,这样我们不必每次都从头到尾的扫描,只需要扫描到记录点为止。 因为后面的都已经是排好序的了。
/*
==========================
功能:冒泡排序(由小到大)
返回:指向链表表头的指针
==========================
*/
struct student *BubbleSort (struct student *head)
{
struct student *endpt; //控制循环比较
struct student *p; //临时指针变量
struct student *p1,*p2;
p1 = (struct student *) malloc (LEN);
p1->next = head; //注意理解:我们增加一个节点,放在第一个节点的前面,主要是为了便于比较。因为第一个节点没有前驱,我们不能交换地址
head = p1; //让head指向p1节点,排序完成后,我们再把p1节点释放掉
for (endpt = NULL; endpt != head; endpt = p) //每次把最终节点记录为已经排序好的链表的首节点
{
for (p = p1 = head; p1->next->next != endpt; p1 = p1->next)
{
if (p1->next->num > p1->next->next->num) //如果前面的节点键值比后面节点的键值大,则交换
{
p2 = p1->next->next; //结合第1点理解
p1->next->next = p2->next; //结合第2点理解
p2->next = p1->next; //结合第3点理解
p1->next = p2; //结合第4点理解
p = p1->next->next; //每一次内for循环结束后p记录从此节点往后都是已经排序号的节点
}
}
}
p1 = head; //把p1的信息去掉
head = head->next; //让head指向排序后的第一个节点
free (p1); //释放p1
p1 = NULL; //p1置为NULL,保证不产生“野指针”,即地址不确定的指针变量
return head;
} 二:选择排序
选择排序的时间复杂度为 O(n)
选择排序是一个不稳定的排序,因为其中相同的元素在排列后的相对顺序可能发生改变
链表的选择排序struct student *checksort(struct stuent *head)
{
struct student *first;//新链表的首指针
struct student *tail;//新链表的尾指针
struct student *p;//当前正在比较的节点指针
struct student *p_min;//最小节点的前驱指针
struct student *min;//最小节点的指针
first=NULL;
while(head!=NULL)
{
for(p=head,min=head;p->next!=NULL;p=p->next)
{
if(p->next->num<min->num)
{
p_min=p;//最小节点的前驱节点指针
min=p->next;//最小节点的节点指针
}
}
}
if(first==NULL)//当排列后的有序链表还是一个空链表时
{
first=min;
tail=min;
}
else{
tail->next=min;
tail=tail->next;
}
//从原先链表中去除最小节点
if(min==head)
{
head=head->next;
}
else{
p_min->next=min->next;
}
if(first!=NULL)
tail->next=NULL;
head=first;
return head;
}直接选择排序
简单选择排序的基本思想:第1趟,在待排序记录r[1]~r
中选出最小的记录,将它与r[1]交换;第2趟,在待排序记录r[2]~r
中选出最小的记录,将它与r[2]交换;以此类推,第i趟在待排序记录r[i]~r
中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完
template<typename T>
void bubblersort( T arr[],int n)
{
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
if(arr[i]>arr[j])
{
T c=arr[j];
arr[j]=arr[i];
arr[i]=c;
}
}三.插入排序
插入排序的基本思想是:每步将一个待排序的记录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
链表的插入算法:struct student * InsertSort(struct student * head)
{
struct student * t;//待插入的节点指针
struct student * first;//剩余的带插入链表节点的首指针
struct student * p,*q;
first=head->next;;
head->next=NULL;
while((first!=NULL)
{
for(t=first,q=head;(q->next!=NULL)&&(q->num>t->num);p=q,q=q->next);//当退出循环时就把t插入到p节点之后q节点之前
first=first->next;//无需链表中的首节点离开插入到有序链表中
if(q==head)//插入到头结点处
head=t;
else
p->next=t;
t->next=q;
}
return head;
}直接插入排序:
直接插入排序的算法思路:(1) 设置监视哨temp,将待插入记录的值赋值给temp;(2) 设置开始查找的位置j;(3) 在数组中进行搜索,搜索中将第j个记录后移,直至temp.key≥r[j].key为止;(4) 将temp插入r[j+1]的位置上
zhijieInsert(T r,int n) { int i,j; T temp; for(i=1;i<n;i++) { temp=r[i] j=i-1; while (j>-1 &&temp.key<r[j].key) { r[j+1]=r[j]; j--; } r[j+1]=temp; } }
也可以写为voidinsert_sort(int*array,unsignedintn)
{
inti,j;
int temp;
for(i=1;i<n;i++)
{
temp=*(array+i);
for(j=i;j>0&&*(array+j-1)>temp;j--)
{
*(array+j)=*(array+j-1);
}
*(array+j)=temp;
}
}
四:快速排序
快速排序是对冒泡排序的一种改进通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序为不稳定的排序
输入:
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 6 | 2 | 7 | 3 | 8 | 9 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 3 | 2 | 7 | 6 | 8 | 9 |
i=2,j=3,key=6
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 3 | 2 | 6 | 7 | 8 | 9 |
{
if(low>=high)
return ;
//把first和last初始化为首尾元素的下标
int first=low;
int last=high;
int key=a[first];
while(first<last)//当首尾元素相遇时循环结束
{
while(first<last&&a[last]>=key)
{
--last;
}
a[first]=a[last]
while(first<last&&a[first]<=key)
{
++first;
}
a[last]=a[first]
}
a[first]=key;
/*循环结束后可以保证比key小的值都在左边,大的都在右边,此时last指向第一个比key大的值的下标,first为key值的下标,需要对两边在此 行排序*/
Qsort(a,low,last-1);
Qsort(a,first+1,high);
}
相关文章推荐
- 数据结构——选择排序、插入排序、冒泡排序、快速排序
- js实现的冒泡排序、选择排序、插入排序、快速排序
- java实现各种排序算法(包括冒泡排序,选择排序,插入排序,快速排序(简洁版))及性能测试
- C语言常用的几种排序算法代码(选择排序,冒泡排序,插入排序,快速排序)
- 简单的排序算法——插入排序,选择排序,交换排序(冒泡排序,快速排序)
- 简单的排序算法——插入排序,选择排序,交换排序(冒泡排序,快速排序)
- java实现冒泡排序,选择排序,插入排序,快速排序(简洁版)及性能测试
- JAVA中排序算法(冒泡排序、选择排序、插入排序、快速排序)
- 冒泡排序,选择排序,插入排序,堆排序,归并排序,快速排序
- PHP四种基础算法详解(冒泡排序、选择排序、插入排序、快速排序)
- 冒泡排序,选择排序,插入排序,快速排序(PHP)
- 8 排序--选择排序,插入排序,冒泡排序,shell排序,快速排序(递归,迭代,改进版本),归并排序
- 常见排序方法(冒泡排序、选择排序、插入排序、希尔排序和快速排序)
- java实现冒泡排序,选择排序,插入排序,快速排序(简洁版)及性能测试
- 用JS实现冒泡排序、插入排序、选择排序、快速排序
- 排序--选择排序,插入排序,冒泡排序,shell排序,快速排序(递归,迭代,改进版本),归并排序
- 内部排序冒泡排序、插入排序、选择排序、快速排序的算法和PHP实现
- java实现冒泡排序,插入排序,选择排序,快速排序
- Go语言实现冒泡排序、选择排序、快速排序及插入排序的方法
- PHP实现插入排序,选择排序,冒泡排序和快速排序