冒泡排序
思路
从后往前两两比较相邻元素的值,若为逆序(A[i-1]>A[i]),则交换两元素,直到序列比较完毕。每趟排序都将未排序列中最小元素放在已排序列的最终位置。
最多执行n-1次,若某一趟排序中没有进行任何交换,说明序列已经有序,则停止排序。
排序过程中,若两元素相同,则不交换,保证稳定性。
代码
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void print(int A[], int length)
{
for (int i = 0; i < length; ++i)
{
printf("%d ", A[i]);
}
}
void swap(int &a,int &b)
{
int temp = a;
a = b;
b = temp;
}
//冒泡排序
void BubbleSort(int A[], int n) {
for (int i = 0; i < n-1; ++i) {
int flag = 1;
for (int j = n - 1; j > i; --j) {
if (A[j - 1] > A[j])
{
swap(A[j - 1], A[j]);
flag = 0;
}
}
if (flag == 1)
{
return;
}
}
}
void test()
{
int A[10];
int length = sizeof(A) / sizeof(A[0]);
srand(time(0));
for (int i = 0; i < length; ++i)
{
A[i] = rand() % 100;//取0-99的随机数 0-99,都为原值,100-199为0-99,以此类推
}
printf("原始序列为:\n");
print(A, length);
BubbleSort(A, length);
printf("\n排序后为:\n");
print(A, length);
}
int main()
{
test();
}
链表实现
思路
数组是从后往前冒泡,而链表特别是单链表不方便从后向前查找,因此可以从前向后把较大的值冒到后面去。
链表排序最好还是要交换节点,而不只是交换值。
交换节点后p指针等于后移了一位
1,交换节点后
指针p与q(p的后一元素指针)交换了位置,实际相当于p已经后移一位,
2,不交换节点
当前元素小于下一元素,p需要手动后移,指向下一个元素(更大的)
3,pre位置不变
无论是否交换,pre指针位置不变,因此通过pre执行后移。
代码
#include<stdio.h>
#include "malloc.h"
#include<stdlib.h>
#include<time.h>
//定义链表结构体
typedef struct Linklist
{
int data;
struct Linklist* next;
}Linklist;
//交换链表中两个节点
void swap(Linklist* pre,Linklist* p, Linklist* q)
{
pre->next = q;
p->next = q->next;
q->next = p;
};
//输出链表节点
void print(Linklist* L)
{
Linklist* p = L;
for (int i = 0; i < L->data; ++i)//L为头结点不能动 否则每次遍历就会改变条件
{
printf("%d ", p->next->data);
p = p->next;
}
printf("\n");
}
void Bubblesort(Linklist* head)//简单选择排序(升序)
{
for (int i = head->data - 1; i > 0; --i)
{
int flag = 1;
Linklist* pre = head;
Linklist* p = pre->next;
for (int j = 0; j < i; ++j)//从第一个元素开始遍历到n-1个元素
{
if (p->data > p->next->data) {//将大的元素冒泡上去
swap(pre, p, p->next);//元素交换后,p指针就相当于前移了一次(数组中只交换值,不改变下标)
flag = 0;
}
pre = pre->next;//不管交换与否,pre位置不变,因此通过pre指针指行后移
p = pre->next;
}
if (flag == 1)
return;
}
}
void test()
{
//建立链表,头结点
Linklist* L = (Linklist*)malloc(sizeof(Linklist));
if (L == NULL) {
printf("内存分配不成功!\n");
}
else
{
L->data = 10;
Linklist* p = L;
srand(time(0));
for (int i = 0; i < L->data; ++i)
{
p->next = (Linklist*)malloc(sizeof(Linklist));
if (p->next) {
p = p->next;
p->data = rand() % 100;//取0-99的随机数 0-99,都为原值,100-199为0-99,以此类推
}
}
p->next = NULL;
printf("原始序列为:\n");
print(L);
Bubblesort(L);
printf("\n排序后为:\n");
print(L);
}
}
int main()
{
test();
return 0;
}
快速排序
思路
快速排序是基于分治法进行的。在待排序列L[1…n]中建立一个元素pivot作为枢轴(常为首元素)。通过一趟排序将序列分为独立的两个部分L[1…K-1]和L[K+1…n]。使L[1…K-1]中所有元素小于pivot,L[K+1…n]中所有元素大于等于pivot,pivot放在其最终位置L[K]上。然后递归地进行多次快速排序,直到所有子表只有一个元素或者为空,则所有元素都放在最终位置。
具体的一趟排序:
low和high指针分别指向首尾元素,pivot取首元素。
从high向左,找到第一个小于pivot的元素,将其替换到low处。
从low向右,找到第一个大于等于pivot的元素,将其替换到high处。
high和low交替向中间搜索元素,直到low==high,此处就是pivot的最终位置
若序列只有一个元素,显然已经有序,该元素就在最终位置处。
具体的递归机制可以看我的这篇帖子:【上机代码】函数调用栈,快速排序与归并排序.
代码
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void print(int A[], int length)
{
for (int i = 0; i < length; ++i)
{
printf("%d ", A[i]);
}
}
//partition实现从low和high向中间扫描序列,以low指向的元素为基准,将序列分为两个部分,基准在中间,左边所有元素小于基准,右边所有元素大于等于基准。
//返回基准值,和排序好的序列
int partition(int A[], int low, int high)
{
int pivot = A[low];
while (low < high) {
while (low < high && A[high] >= pivot)
--high;
A[low] = A[high];
while (low < high && A[low] <= pivot)
++low;
A[high] = A[low];
}
A[low]= pivot;
return low;
}
//基于递归实现,先按基准排序,然后分别递归处理基准左右的子表,子表长度>1时就继续划分,直到所有子表被处理完毕。
void QuickSort(int A[], int low, int high) {
if (low < high) {
int pivotpos = partition(A, low, high);
QuickSort(A, low, pivotpos - 1);
QuickSort(A, pivotpos + 1, high);
}
}
void test()
{
int A[10];
int length = sizeof(A) / sizeof(A[0]);
for (int i = 0; i < length; ++i)
{
A[i]= rand() % 100;//取0-99的随机数 0-99,都为原值,100-199为0-99,以此类推
}
printf("原始序列为:\n");
print(A, length);
QuickSort(A, 0, length-1);
printf("\n排序后为:\n");
print(A, length);
}
int main()
{
test();
}