编程珠玑笔记--排序

首先来个插入排序

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include < stdio.h >
 
void swap(int *x, int *y)
{
     int t = *x;
     *x = *y;
     *y = t;
}
void insert_sort(int *x, int length)
{
     int i, j;
     for (i = 1; i < length ; i++)
         for ( j = i ; j > 0 && x[j-1] > x[j]; j--)
             swap(&x[j-1], &x[j]);
}
 
int main(void)
{
     
     int i, a[] = {42, 20, 17, 13, 28, 14, 23, 15};
     insert_sort(a, 8);
     for (i = 0; i < 8;i++)
        printf("%4d", a[i]);    
     return 0;
}

在第二个for循环中,总是给t赋予相同值x[i],可以将其移出第二个for循环

?
1
2
3
4
5
6
7
8
9
10
11
void insert_sort(int *x, int length)
{
     int i, j;
     for (i = 1; i < length ; i++)
     {
         int t = x [i];
         for ( j = i ; j > 0 && x[j-1] > t; j--)
             x[j] = x[j-1];
         x[j] = t;
     }
}

一种简单的快速排序

排序数组时,将数组不停分成两个小部分,进行递归排序,分别用l和u表示数组排序部分的下界和上界,递归结束条件是待排序部分的元素个数小于2.

然后围绕某一值t对数组进行划分,重新组织x[a….b],并计算中间元素的下标m,使得所有<t在m左,所有>t在m右

|a      <t         |m       >= t     |i            ?未处理部分            b|

?
1
2
3
4
m = a -1;
for i = [a, b]
     if x[i] < t
         swap(++m, i);
?
1
2
3
4
void q_sort(int l, int u)
{
     if (l >= u)
         return ;
?
1
m = l;
?
1
for (int i = l +1; i <= u; i++)
?
1
if (x[i] < x[l])
?
1
swap(++m, i);
?
1
2
3
4
        swap(m, l);
     qsort(l, p -1);
     qsort(p + 1, u);
}

 

从右侧划分,完整代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void qsort2(int l, int u)
{
     if (l >= u)
         return;
     m = i = u + 1;
     do
     {
       while (x[--i] < x[l]) ;   
          swap(i, --m); 
     }
         while (i != l)
     qsort2(l, m - 1);
     qsort2(m + 1, u);
}

当元素相同时,为最坏情况o(n*n),使用双向划分可解决问题,变为o(nlog(n))

?
1
主循环中有两个循环,第一个内循环将i向右移过小元素,遇到大元素停止;第二个内循环向左移过大元素,遇到小元素停止。
?
1
主循环测试这两个下标若交叉,则交换它们的值。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void qsort3(int l, int u)
{
     if (l >= u)
         return ;
     int i = l, j = u + 1, t = x[l];
     while (1)
     {
         while (x[j] > t) j--;
         while (i <= u && x[i] &l t ; t) i++;
         if (i > j)
             break;
         swap(i, j);
     }
     swap(l, j);
     qsort3(l, j - 1);
     qsort3(j + 1, u);
}
?
1
  

以上都是按照第一个元素进行划分,随机选择划分元素可得到更好的性能 swap(l, randint(l, u));.

?
1
2
3
4
5
6
7
8
9
int bigrand()
{
     return RAND_MAX*rand() + rand();
}
 
int randint(int l, int u)
{
     return l + bigrand() % (u - l + 1);
}

对于任意n元输入数组,快速排序时间都正比于nlogn。

快速排序会花费大量时间来排序很小数组,如果用插入排序累排序小数组,程序速会更快。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void qsort4(int l, int u)
{
     if (u - l < cutoff )
         return;
     swap(l. randint(l, u));
     int t = x [l], i = l , j = u + 1;
     for (;;)
     {
         while (i <= u && x[i] < t) i++;
         while (x[j] > t) j--;
         if (x > j)
             break;
         swap(i, j);
     }
     swap(j, l);
     qsort4(l, j - 1);
     qsrt4(j + 1, u);
}
 
void test()
{
       qsort4(0, length - 1)
       insert_sort(x, length);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值