- 冒泡排序:把元素看成一系列的气泡,小的在下,大的再上,再上升期间要相邻的气泡进行比对,大的数往上冒泡。最好的情况下(整个序列是已经排好序的),但仍要进行1/2 n2(等差数列的和)次比较,所以最好情况下的时间复杂度是O(n2),最坏情况下是整个数列完全为逆序,比较和交换都要进行1/2 n2次,总次数是n2次,时间复杂度是O(n2),平均复杂的也是O(n2)。
- 插入排序,对一个序列(一开始里面包含的数只有1个)已经排好的序列插入一个数(假设在数组中从小到大排),序列外的元素首先与最大值比较,比最大值大的话存储位置不变,然后序列元素量增加,小的话与最大值交换位置,在与次最大值比较,然后重复,直到找到插入的正确位置。在最坏情况下,即是整个序列正好是逆序排列,需要比较1/2 n2次,交换也是1/2 n2,所以时间复杂度为O(n2)。最好情况下,即是整个序列正好是顺序排列,需要比较n-1次,交换0次时间复杂度为O(n)。根据时间复杂度计算规则(次方留最大,舍常数),他的平均的时间复杂度为:O(n2),当序列中的数据量较小时,选择插入排序会快很多。
- 选择排序:在无序的序列中,从某一端的一个元素开始,依次与后面的元素比较大小,满足条件的进行交换,接着从第二个元素开始再与后面的进行逐一比对,接着重复到最后的n-1个元素。最好情况下是顺序排列,无需交换,但比较仍然需要进行1/2 n2次,最坏情况下则额外要交换1/2 n2次。所以平均时间复杂度为O(n2)。
- 快速排序算法:将序列排成三段,分为a[left~i] a[i] 和a[i+1~right],使左端的数都满足小于a[i],右端的数大于a[i]。然后再次对左端序列采取上述办法,直到左端的子序列的元素量为1。然后再对右端采取上述办法,也直到右端的子序列元素量为1。
- 由于篇幅有限,我们仅对快速排序进行说明。递归方法如下
typedef int Item;
int partition(Item a[],int l,int r)
{
int i = l-1,j=r;
Item v = a[r];
int t;
for(;;){
while(less(a[++i],v));//找大于v的数
while(less(v,a[--j]))if(j == l)break;//找小于v的数,要是减到坐标小于传进来的数组下标最小值就跳出
if(i>=j)break;//如果i的坐标是之前已经交换过的值的坐标,就跳过
swap(a[i],a[j]);//交换值
printf("交换的值为:%d %d \n",a[i],a[j]);
}
swap(a[i],a[r]);//再将下次用来快速排序的对照值替换至a[i]
printf("\n");
printf("对照值的坐标是:%d\n",i);
for(int i = 0;i<9;i++)printf(" %d ",a[i]);
printf("\n");
return i;//返回新对照值的坐标
}
void sort(Item a[],int l,int r)
{
if(r<=l)return;//传进来的数组长度为1时就开始返回
int i = partition(a,l,r);//先进行第一次排序,获得划分两个数组的下标先
sort(a,l,i-1);
sort(a,i+1,r);
}
int main()
{
int i=0;
int a[8] = {3,1,2,5,6,7,9,10};
sort(a,0,7);
while(a[i]){
printf("%d",a[i++]);
}
}
- 非递归的快速排序,可以用栈或者队列。栈的后进先出的特性可以模仿递归调用。问题的关键是给处理函数分配需要处理数组的区段,即是数组的下标。代码如下
typedef int ListItem;
typedef struct snode *Snode;
typedef struct snode{
ListItem element;
Snode next;//栈顶
}Simul;
typedef struct stack *Stack;
typedef struct stack{
Snode top;//栈顶
Snode curr;//表中
}Simul1;
Stack ListInit()
{
Stack L = (Stack)malloc(sizeof(* L));
L->top = NULL;
L->curr = NULL;
return L;
}
int IsEmpty(Stack L)
{
return L->top == NULL;
}
void ListInsert(Stack L,ListItem x)//只能在栈顶插入
{
Snode K = (Snode)malloc(sizeof(* L));
K->element = x;
K->next = L->top; //注意这里的top不是栈中元素
L->top = K;
}
int ListDellete(Stack L)//只能在栈顶删除,所以只需要传递L即可
{
if(IsEmpty(L)) return 0;
L->top = L->top->next;
}
int partition(int a[],int l,int r)
{
int i = l-1,j=r;
int v = a[r];
int t;
for(;;){
while(less(a[++i],v));//找大于v的数
while(less(v,a[--j]))if(j == l)break;//找小于v的数,要是减到坐标小于传进来的数组下标最小值就跳出
if(i>=j)break;//如果i的坐标是之前已经交换过的值的坐标,就跳过
swap(a[i],a[j]);//交换值
}
swap(a[i],a[r]);//再将下次用来快速排序的对照值替换至a[i]
printf(" %d ",i);
return i;//返回新对照值的坐标
}
void sort(int a[],Stack L)
{
int i,l,r;
while(!IsEmpty(L)){
l = L->top->element;r = L->top->next->element;//将栈值取出
ListDellete(L);//删除已经取出的栈的值
ListDellete(L);
if(r<=l)continue;
int i = partition(a,l,r);
if(r-i>i-l){
ListInsert(L,r);
ListInsert(L,i+1);
ListInsert(L,i-1);
ListInsert(L,l);
}
else{
ListInsert(L,i-1);
ListInsert(L,l);
ListInsert(L,r);
ListInsert(L,i+1);
}
}
}
int main(){
int i = 0;
int a[11] = {3,1,2,4,6,7,5,9,8,10};//建议数组容量比实际存储值加一,防止末尾极端情况溢出。
Stack L = ListInit();
ListInsert(L,9);
ListInsert(L,0);
sort(a,L);
while(a[i]){
printf(" %d ",a[i]);
i++;
}
}
- 总结,我是被另个一博主的文章点拨到的,思路十分清晰,对我帮助很大。在这里附上链接:该文链接