因为最近在期末复习,就整理了一下算法,由难到易展示一下,不需要概念的直接跳到代码就好。(排序为左小右大)
请一边看这个网站的动图,加深理解
算法步骤图
前面是一些概念:
如何优秀编程:
可读性:别人看得懂
可靠性:怎么测试都可以
可维护性:接口友好
可复用性:易于被别人使用,合理注释
考虑:复杂度(空间,时间),可行度,正确度
空间复杂度和时间复杂度
空间复杂度:所占储存的体积
时间复杂度:运行语句的条数
快排的平均时间复杂度为nlogn
算法的伪代码形式
<, =, >, >=, <=,<>//运算符
or, and, not//逻辑运算符
start
a,b,sum, equal: Integer//定义
write('please input two numbers')//写
read(a,b)//读
sum<-a+b//赋值
write('the first number is',a,'the second is',b,'the sum is',sum)
//for 语句
for i varying from 1 to 10
write('Hello');
end for
//if 语句
**if** a<b **then**
equal<- -1
**if** a>b **then**
equal<- 1
**if not**
equal<- 0
**end if**
//switch语句
write(‘give me a number’)
read(n)
in case of n is
0:write(‘zero’)
1:write(‘one’)
2:write(‘two’)
otherwise
write(‘too big’)
end case
//do while 语句
num: Integer
read(num)
repeat/do
num++;
while num<10//num<10时执行
until num>=10//num >=10 时退出
end while
end
接下来就可以用三种形式表示程序啦。
1-快速排序:
思路:取出最左边的数作为基准数(pivot),要达到pivot左侧比它小,右侧比它大,扫描从右侧第一和左侧第一分别进行,先看右侧,找到在右侧,但比pivot小的数,放到左边,覆盖pivot原来的位置,再找到左侧但比pivot大的数,放到右边,以此类推,直到左右指针相遇,即为pivot所在位置,再分别对pivot左右进行快排。(请查看上述链接,思路基本一样,但它的pivot从中间开始选择)
代码:
void quicksort(int low, int high,int arr[]) {
//思想:选取一个值,把它排到它应该在的位置(这里选取第一个)
//即它的左侧都要比它小,它的右边都要比它大
//不满足就把右侧的数换到左边/把左边换到右边(通过一个空位)
//直到左右相遇即为pivot的正确位置
//再用递归分别快排pivot左侧和右侧的数组达成有序
//直到只有一个数,退出递归
int* left = arr+low;
int* right = arr + high;
int pivot = left;//选取pivot
//我们要达成的状态:pivot右边比他大,左边比他小
if (low > high) {
return;
}//用于退出递归。
while (left<right) {
while (right >= pivot&&left<right) {//要是右边比他大,检验合格,下一个
right--;//注意还要避免在while循环中超出范围
}
*left = *right;//检验不合格,右边要放到左边来
//因为设定pivot初始等于最左值,所以最左值重复了两次,原最左位可以给右边小于pivot的值
//同时原本在右边的值已经到左边了,它现在也有两个了.
//但我们需要的正确位置是它在pivot左侧, 所以等一下它在右边的重复值也同样被覆盖
//其实我们设定的变量pivot相当于为原数组腾挪出了一个空位用于排序,
//而我们最终要确定的只是pivot的正确位置
//所以,pivot存在变量里,左右两边互相覆盖
//left++;//因为挪过来的值一定比pivot小,所以检验合格,不再重复比较
//错误!此步不可以随便加入,因为可能前面已经因为right--退出了小循环
//若再加会造成left>right,所以当此时left,right就已经指向同一个时,自己交换自己是可以的
while (left <=pivot&&left<right) {
left++;//与右侧对称
}
*right = *left;//左值覆盖右值
// right--;
}
//最后的结局是左右指针指向同一个位置,而这个位置就是pivot的归宿
*left = pivot;//此时left==right,写哪个都没事
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
putchar('\n');
//现在我们已经完成了一个数的快排,现在可以用递归实现两边的快排了
int mid = left - arr;//地址值相减,得到在数组中的位置
quicksort(low, mid-1, arr);
quicksort(mid+ 1, high, arr);
}
注意:
2. 如果从左选取pivot则要先把右边的数挪过来,右侧反之
3. 本质是取出pivot放在变量里再依次左右挪动
4. 注意递归和退出递归条件
算法语言
//仍是左小右大的方向
function quicksort(begin,end,tab)
//注释变量类型
begin,end:integer(I)//I -->input,O–>output
tab:array(I)
left,right,pivot:integer pointer
left<–tab+begin
right<–tab+right
pivot<–tab+begin
if begin>end then
//因为排到最后一个数时下一次begin会直接<end,
//注意不可以用==,因为下面递归时用的是left-tab-1,会直接跳过,导致递归无法中断
return
while left<>right and
while *pivot<*right and left<>right then
right–
end while
** left=right//是直接覆盖,不是交换,而且是左右值变动
while *pivot>*left and left<>right then
left++
end while
*right=*left
quicksort(begin,left-tab-1,tab)
quicksort(left-tab+1,end,tab)
end
流程图
2-融合排序
程序
void merge(int tab[],int begin, int end) {
//思想:先吧数组对分到最小单元
//再把每个最两个小单元进行融合
//再融合更大级的单元
//先将数组分成俩
//merge用于将一个有序数组分成两份并融合得到更长的有序数组
//merge_devide用于递归使数组对分
int mid = (end+begin)/2;
int tab1[10] = { 0 };
int tab2[10] = { 0 };
int p1 = 0;
int p2 = 0;
for (int i = begin; i <= end; i++) {
if (i <=mid) {
tab1[p1] = tab[i];
p1++;
}//一半给tab1
else {
tab2[p2] = tab[i];
p2++;
}//剩下给tab2
}
//用于将两个有序数组融合成一个新的有序数组
p1 = 0;
p2 = 0;
int p = begin;
int n1 = mid-begin+1;
int n2 = end-mid;
while (p1<n1&&p2<n2) {
//当两个要合并的数组都没有用完
//依次比较两数组各自位大小
//小的放入tab,达成有序
if (tab1[p1] < tab2[p2]) {
tab[p] = tab1[p1];
p1++;
p++;
}
else {
tab[p]= tab2[p2];
p2++;
p++;
}
}
//处理剩下的数字
if (p1 ==n1) {
//如果第一个数组用完了
for (p2; p2 <n2; p2++) {
tab[p]= tab2[p2];
p++;
}
}
else {
//第二个数组用完了
for (p1; p1 <n1; p1++) {
tab[p] = tab1[p1];
p++;
}
}
for (int i = begin; i <=end ; i++) {
printf("%d ", tab[i]);
}
putchar('\n');
}
void merge_divide(int tab[],int begin,int end) {
if (begin == end)
return;//只剩一个数,不再分割
int mid = (end+begin)/2;
merge_divide(tab,begin,mid);//继续分割
merge_divide(tab, mid+1, end);
merge(tab, begin, end);//融合
}
注意:
- 注意融合后剩下的数字
- 注意递归
算法语言
function merge(tab,begin,end)
tab:Integer array(I)
begin,end:Integer(I)
tab1={0}
tab2={0}
mid<-- (begin+end)/2
for i varying from begin to end
if i<=mid then
tab_1[i]=tab[i]
if not
tab_2[i]=tab[i]
end if
end for
p1<–0
p2<–0
p<–begin
n1<–mid-begin+1
n2<–end-mid
while p1<n1 and p2<n2
if tab1[p1]>tab2[p2] then
tab[p]<–tab2[p2]
p2++
p++
if not
tab[p]<–tab1[p1]
p1++
p++
end if
end while
if p1==n1 then
while p2<n2
tab[p]=tab2[p2]
p++
p2++
end while
if not
while p1<n1
tab[p]=tab[p1]
p++
p1++
end while
end if
function divide_merge(tab,begin,end)
if begin==end then
return 0
end if
mid<–(end+begin)/2
divide_merge(tab,begin,mid)
divide_merge(tab,mid+1,end)
merge(tab,begin,end)
3-插入排序
void insert(int tab[], int num) {
//使前面n项有序,后面的数逐渐插入前面的有序数列,有点像冒泡
for (int n = 0; n <num; n++) {
//控制循环次数
for (int m = n+1 ; m >0; m--) {
//比较该项与前一项
if (tab[m] < tab[m-1]) {
int replace = tab[m];
tab[m] = tab[m-1];
tab[m-1] = replace;
}
}
}
//打印
for (int i = 0; i < 10; i++) {
printf("%d ", tab[i]);
}
putchar('\n');
}
4-选择排序
void select(int tab[], int num) {
//思想:选择最大值与最左交换
for (int i = 0; i < num; i++) {//无序数为0~num-i,控制循环次数
int max = 0;//每次假设最大的是第一个
for(int j=1;j<=num-i;j++)//需要比较第二个到无序最后一个
if (tab[j] > tab[max]) {
max = j;//找到最大的数字所对下标
}
//交换最大值和最后一个
int replace = tab[num-i];
tab[num-i] = tab[max];
tab[max] = replace;
}
//打印
for (int i = 0; i < 10; i++) {
printf("%d ", tab[i]);
}
putchar('\n');
}
5-冒泡排序
void bubble(int tab[],int num) {
//思想:从左往右,大的往右边交换
//确保每次换到无序最左边的是最大的
//从而达到排序
for (int q = 0; q < num; q++) {
//控制循环次数
for (int j = 0; j < num - q; j++) {
//从q开始冒泡,则此时0~num-q均无序
//一直比较到最后两个无序数字结束
if (tab[j] > tab[j + 1]) {
int replace = tab[j];
tab[j] = tab[j + 1];
tab[j + 1] = replace;
}
}
}
for (int i = 0; i <= num; i++) {
printf("%d ", tab[i]);
}
putchar('\n');
}
注意:
可以看到最后三种排序都是用两层for实现的,值得注意的是第一层只是控制循环次数的,其局部变量不能放在第二层里,用了就错。
主函数调用:
int main() {
int arr[] = { 23,11,56,3,0,78,12,52,9,43 };
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
putchar('\n');
//quicksort(0, 9, arr);//快排
//merge_divide(arr,0,9);//融合
//bubble(arr, 9);//冒泡
//select(arr,9);//选择
// insert(arr, 9);//插入
return 0;
}
菜鸟首发,欢迎讨论。