排序算法

# 冒泡排序

1.算法步骤

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个。

持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

void bubble_sort(int arr[], int len) {

        int i, j, 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;

                        }

}

## 选择排序

1.算法步骤

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。

再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

重复第二步,直到所有元素均排序完毕。

void swap(int *a,int *b) //交換兩個變數

{

    int temp = *a;

    *a = *b;

    *b = temp;

}

void selection_sort(int arr[], int len) 

{

    int i,j;

    for (i = 0 ; i < len - 1 ; i++) 

    {

                int min = i;

                for (j = i + 1; j < len; j++)    //走訪未排序的元素

                        if (arr[j] < arr[min])    //找到目前最小值

                                min = j;    //紀錄最小值

                swap(&arr[min], &arr[i]);    //做交換

        }

}

## 插入排序

1.算法步骤

将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。

从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)

void insertion_sort(int arr[], int len){

        int i,j,key;

        for (i=1;i

                key = arr[i];

                j=i-1;

                while((j>=0) && (arr[j]>key)) {

                        arr[j+1] = arr[j];

                        j--;

                }

                arr[j+1] = key;

        }

}

## 归并排序

1.算法步骤

申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;

设定两个指针,最初位置分别为两个已经排序序列的起始位置;

比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;

重复步骤 3 直到某一指针达到序列尾;

将另一序列剩下的所有元素直接复制到合并序列尾。

int min(int x, int y) {

    return x < y ? 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) {

            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;

            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);

}

## 快速排序

1.算法步骤

从数列中挑出一个元素,称为 "基准"(pivot);

重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

typedef struct _Range {

    int start, end;

} Range;

Range new_Range(int s, int e) {

    Range r;

    r.start = s;

    r.end = e;

    return r;

}

void swap(int *x, int *y) {

    int t = *x;

    *x = *y;

    *y = t;

}

void quick_sort(int arr[], const int len) {

    if (len <= 0)

        return; // 避免len等於負值時引發段錯誤(Segment Fault)

    // r[]模擬列表,p為數量,r[p++]為push,r[--p]為pop且取得元素

    Range r[len];

    int p = 0;

    r[p++] = new_Range(0, len - 1);

    while (p) {

        Range range = r[--p];

        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[p++] = new_Range(range.start, right);

        if (range.end > left) r[p++] = new_Range(left, range.end);

    }

}

## 堆排序

1.算法步骤

创建一个堆 H[0……n-1];

把堆首(最大值)和堆尾互换;

把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;

重复步骤 2,直到堆的尺寸为 1。

void swap(int *a, int *b) {

    int temp = *b;

    *b = *a;

    *a = temp;

}

void max_heapify(int arr[], int start, int end) {

    // 建立父節點指標和子節點指標

    int dad = start;

    int son = dad * 2 + 1;

    while (son <= end) { // 若子節點指標在範圍內才做比較

        if (son + 1 <= end && arr[son] < arr[son + 1]) // 先比較兩個子節點大小,選擇最大的

            son++;

        if (arr[dad] > arr[son]) //如果父節點大於子節點代表調整完畢,直接跳出函數

            return;

        else { // 否則交換父子內容再繼續子節點和孫節點比較

            swap(&arr[dad], &arr[son]);

            dad = son;

            son = dad * 2 + 1;

        }

    }

}

void heap_sort(int arr[], int len) {

    int i;

    // 初始化,i從最後一個父節點開始調整

    for (i = len / 2 - 1; i >= 0; i--)

        max_heapify(arr, i, len - 1);

    // 先將第一個元素和已排好元素前一位做交換,再重新調整,直到排序完畢

    for (i = len - 1; i > 0; i--) {

        swap(&arr[0], &arr[i]);

        max_heapify(arr, 0, i - 1);

    }

}

int main() {

    int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };

    int len = (int) sizeof(arr) / sizeof(*arr);

    heap_sort(arr, len);

    int i;

    for (i = 0; i < len; i++)

        printf("%d ", arr[i]);

    printf("\n");

    return 0;

}

## 计数排序

1.算法步骤

(1)找出待排序的数组中最大和最小的元素

(2)统计数组中每个值为i的元素出现的次数,存入数组C的第i项

(3)对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)

(4)反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,640评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,254评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,011评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,755评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,774评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,610评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,352评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,257评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,717评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,894评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,021评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,735评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,354评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,936评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,054评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,224评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,974评论 2 355

推荐阅读更多精彩内容