c语言 排序算法

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
// sort_algorituhm.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
 
#include <iostream>
#include<algorithm>
using namespace std;
#define elemtype int
 
 
 
//冒泡排序法,组个遍历,大数往后,每次都是"完全遍历",从0开始
void sort_bubbling(elemtype *p, int sort_len) {
    elemtype temp = 0;
    int i, j;
    for(i=0; i < (sort_len-1);i++)
        for (j = 0; j < (sort_len - 1 - i); j++)
        {
            if (p[j] > p[j + 1])
            {
                temp = p[j];
                p[j] = p[j + 1];
                p[j + 1] = temp;
            }
 
        }
}
//选择最大的值放在序列最后,重点:记录当前轮询周期下数列最值下标,找出后直接与数列尾端交换
//每次比较后,因为已经找出了最大值放到最后,下一次数列比较只到最值之前一个数即可
void sort_select(elemtype* p, int sort_len) {
    elemtype temp = p[0];
 //   elemtype Min_num = p[0];
    int index = 0;
    int i,j;
 
    for (j = 0; j < (sort_len-1); j++)
    {
        for (i = 0; i < (sort_len-j); i++)
        {
            if (p[i] > temp)
            {
                temp = p[i];
                index = i;
            }
        }
        temp = p[sort_len-j-1];
        p[sort_len-j-1] = p[index];
        p[index] = temp;
        index = 0;
        temp = p[index];
    }
 
}
//插入排序法,重点:记录当前正在比较的数组元素下标,逐次之前的元素比较交换位置,直达插入完成
void sort_insert(elemtype* p, int sort_len)
{
    int i, j, key;
    for (i = 1; i < sort_len; i++) {
        key = p[i];
        j = i - 1;
        while ((j >= 0) && (p[j] > key)) {
            p[j + 1] = p[j];
            j--;
        }
        p[j + 1] = key;
    }
}
//希尔排序算法
void sort_shell(elemtype* p, int sort_len)
{
    int gap, i, j;
    int temp;
    for (gap = sort_len >> 1; gap > 0; gap >>= 1) //获得每次的分隔数
        for (i = gap; i < sort_len; i++)//按照分隔数,将数组分割为多组分别进行插入排列,这里的i++使得不同分组的前几个数在下一个gap到来之前并行分别排序
        {
            temp = p[i];    //插入排序法中,正在比较的数组元素
            //按指定间隔遍历链表,寻找插入位置,因为for循环开始时,j = i - gap
            //使得分的小组数列从建立起就是升序排列,即插入排序法
            for (j = i - gap; j >= 0 && p[j] > temp; j -= gap)
                p[j + gap] = p[j];
            p[j + gap] = temp;    
        }
}
elemtype min(elemtype x, elemtype y)
{
    return y > x ? x : y;
}
//归并排序 ,迭代法,将数组向下分割为单个元素,再对单个元素进行多次归并
void merge_sort(int arr[], int len) {
    int* a = arr;
    int* b = (int*)malloc(len * sizeof(int));
    int seg, start;
    for (seg = 1; seg < len; seg += seg) {
        for (start = 0; start < len; start += seg * 2) {
            //第一次归并,将数组排序为2个一组的(尾部单独算),升序排列的数列
            //第二次归并,将排序好的2个一组的数列,小端比小端开始,依次比较组合为4个一组的(尾部单独算),升序排列的数组
            //                           .............
            //第n次归并,将len/2长度的两个排序好的数组,小端开始,,依次比较完成归并
            int low = start, mid = min(start + seg, len), high = min(start + seg * 2, len);
            int k = low;
            int start1 = low, end1 = mid;
            int start2 = mid, end2 = high;//start1,start2为每次比较的有序数组的首地址
            //下面三句完成两个升序数组的升序合并
            while (start1 < end1 && start2 < end2)
                b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
            while (start1 < end1)   //因为是已经排序好的数列,小值已经比另一数列最大值大了,后面直接复制就行
                b[k++] = a[start1++];
            while (start2 < end2)
                b[k++] = a[start2++];
        }
        int* temp = a;
        a = b;
        b = temp;
    }
    if (a != arr) {
        int i;
        for (i = 0; i < len; i++)
            b[i] = a[i];
        b = a;
    }
    free(b);
}
//归并排序 递归法,将数组向下分割为单个元素,再对单个元素进行多次归并
void sort_merge_recursive(int* a, int* b,int start,int end) {
    if (start >= (end-1)) return; //start指向最后是,表示当前递归遍历完毕,开始返回
    int seg = (end - start)/2;
    int low = start, mid = min(start + seg, end), high = end;
    int start1 = low, end1 = mid;
    int start2 = mid, end2 = high;//start1,start2为每次比较的有序数组的首地址
    sort_merge_recursive(a, b, start1, end1);
    sort_merge_recursive(a, b, start2, end2);
    int k = start;
    int i = 0;
    //下面三句完成两个升序数组的升序合并
    while (start1 < end1 && start2 < end2)//将相邻两块 seg 数组,从首端开始比较,有序插入到b
        b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
    while (start1 < end1)   //处理start1-end1之间剩余的数据,因为是已经排序好的数列,小值已经比另一数列最大值大了,后面直接复制就行
        b[k++] = a[start1++];
    while (start2 < end2) //处理start2->end2之间剩余的数据
        b[k++] = a[start2++];
    for (i = start;i<end;i++)
    {
        a[i] = b[i];
    }
}
void sort_My_merge_recursive(int arr[], int len)
{
    int* b = (int*)malloc(len * sizeof(int));
    sort_merge_recursive(arr, b,0,len);
    free(b);
}
 
//快速排序,迭代法<br>
typedef struct _Range {//用于记录当前分区起点与终点
    int start, end;
}Range;
Range new_Range(int s, int e)
{
    Range r = {0,0};
    r.start = s;
    r.end = e;
    return r;
}
void swap(int *x,int *y) {
    int t = *x;
    *x = *y;
    *y = t;
}
void sort_quick(int arr[], const int len)
{
    if (len <= 0) return;   // 避免len等於負值時引發段錯誤(Segment Fault)
    Range* r = (Range*)malloc(sizeof(Range) * len);           // r[]模擬列表,p為數量,r[p++]為push,r[--p]為pop且取得元素
    if (r == NULL) return;
    int ptop = 0;
    r[ptop++] = new_Range(0, len - 1);
    while (ptop)
    {
        Range range = r[--ptop];
        if (range.start >= range.end) continue;
        int mid = arr[(range.start + range.end) / 2];// 選取中間點為基準點
        int left = range.start, right = range.end;
        do
        {
            while (arr[left] < mid) left++;
            while (arr[right] > mid) right--;
            if (left <= right)
            {
                swap(&arr[left],&arr[right]);
                left++;
                right--; //移动指针以继续
            }
        } while (left <= right);
        if(range.start<right) r[ptop++] = new_Range(range.start, right);
        if(range.end> left) r[ptop++] = new_Range(left, range.end);       
    }
}
//快速排序,递归法<br>//重点是 以数组中间值(随机的)为中线,将数组划分为上下两部分,将大于中间值的数值放到下部,小于中间值的数值放到下半部分 ,然后往下重复细分,直至返回
void sort_quick_rcursive(int arr[],int start,int end)
{
    if (start >= end)return;
    int left = start, right = end;
    int mid = arr[(start + end) / 2];
    do
    {
        while (arr[left] < mid) left++;
        while (arr[right] > mid) right--;
        if (left <= right)
        {
            swap(&arr[left], &arr[right]);
            left++;
            right--; //移动指针以继续
        }
    } while (left <= right);
    sort_quick_rcursive(arr, start, right);
    sort_quick_rcursive(arr, left, end);
}
void sort_My_quick_rcursive(int arr[], int len)
{
    sort_quick_rcursive(arr, 0, len - 1);
}
//堆排序
void my_heapify(int arr[],int dad_index,int len)//最大堆生成
{
    int son = dad_index * 2 + 1;
    while (len > son)//使用while遍历挂在该父节点之后所有节点,避免因为数值调换引起的最大堆出错
    {
        if ((son + 1) < len  && arr[son] < arr[son+1])//获取子节点中大值
        {
            son++;
        }
        if (arr[dad_index] >= arr[son])
            return;
        swap(&arr[dad_index],&arr[son]);
        dad_index = son;                           
        //父亲下标指向与之调换的儿子下标,进行以该儿子下标为父亲节点的最大堆生成,避免因为数值调换引起的最大堆出错(父节点值不是最大)
        son = dad_index * 2 + 1;
    }
}
void sort_heap(int arr[], int len)
{
    int i, j;
    for (i = len / 2 + 1; i >= 0; i--)
        my_heapify(arr, i, len);//建立最大堆
    for (i = len - 1; i > 0;i--)//在最大堆上操作
    {
        swap(&arr[0],&arr[i]);//将当前最低节点(较上层较小)与max值交换
        my_heapify(arr, 0,i-1);//从根节点0开始,交换后的小值不断向下沉淀,大值不断上浮,i-1是为排除有序数列
    }
}
//计数排序,用于0~99内计数
void counting_sort(int* ini_arr, int* sorted_arr, int n) {
    int* count_arr = (int*)malloc(sizeof(int) * 100);
    int i, j, k;
    for (k = 0; k < 100; k++)   //初始化count_arr,每个数据重复计数初始为0
        count_arr[k] = 0;
    for (i = 0; i < n; i++)
        count_arr[ini_arr[i]]++;//直接在数据范围内对重复数据进行重复计数
    for (k = 1; k < 100; k++)//
        count_arr[k] += count_arr[k - 1];//向后叠加计数值,后一个值储存全面所有值数量和,间接获得了每个值排序后的序号
    for (j = n; j > 0; j--)
        sorted_arr[--count_arr[ini_arr[j - 1]]] = ini_arr[j - 1];
    //填充每个数据到排序后数字应该到的位置
    //count_arr[ini_arr[j - 1]]:当前数据应在地址,同时地址减一,应对数据重复情况,向后填充
    free(count_arr);
}
//基数排序
void sort_radix(int* p, int len)
{
    int* sorted_arr = (int*)malloc(sizeof(int) * len);
    int BASE = 10;//取余10
    int exp = 1;//从1开始除,num/exp%BASE, 处理完一轮exp = exp*BASE 依次获得个位、十位...
    int max_num = p[0], i;
    for (i = 1; i < len; i++)//获取最大值,判断循环结束条件
    {
        if (p[i] > max_num) max_num = p[i];
    }
    while (max_num / exp >0)
    {
        int count_arr[10] = {0};
        for (i = 0; i < len; i++)
        {
            count_arr[p[i] / exp % BASE]++;//直接在数据范围内对重复数据进行重复计数
        }
        for (i = 1; i < len; i++)
        {
            count_arr[i] += count_arr[i - 1];//向后叠加计数值,后一个值储存全面所有值数量和,间接获得了每个值排序后的序号
        }
        for (i = len-1; i >= 0; i--)
        {
            sorted_arr[--count_arr[p[i] / exp % BASE]] = p[i];
        }
        for (i = 0; i < len; i++)
        {
            p[i] = sorted_arr[i];
        }
        exp = exp * BASE;
    }
}
 
int main()
{
    elemtype arr[] = { 12,32,34,13,64,234,7,2,5652,34 };
    int loop = 0;
    int n = 10;
    sort_bubbling(arr,n);<br>
    for (; loop < n; loop++)
    {
        printf("%d  ", arr[loop]);
    }
 
    printf("\n");
    system("pause");
}

  

posted @   百叶集  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示