计算机程序就是数据结构加算法。可见算法在计算机世界的重要性,本文所述的算法是指基础通用的查找和排序算法,其是其他更复杂算法的基础,总结在此以备将来查阅。
排序算法
排序算法又分为好多种
- 简单排序(Simple sorts)
1.1 插入排序(Insertion sort)
1.2 选择排序(Selection sort) - 有效排序(Efficient sorts )
2.1 Merge sort (归并排序)
2.2 Heapsort (堆排序)
2.3 Quicksort (快速排序) - 冒泡排序及其变种(Bubble sort and variants )
3.1 Bubble sort (冒泡排序)
3.2 Shell sort (希尔排序)
3.3 Comb sort (梳排序) - 分布排序(Distribution sort )
4.1 Counting sort(计数排序)
4.2 Bucket sort(桶排序)
4.3 Radix sort(基数排序)
简单排序
插入排序
算法:相当与将要排序的数组中的元素一个一个取出,插入新的空数组中,插的过程中进行排序
平均时间复杂度:n*n
最好时间复杂度:nC#
代码示例
public static int InsertionSort(int[] numArray)
{
for (int i = 1; i < numArray.Length; i++)
{
int j = i;
while (j > 0)
{
if (numArray[j - 1] > numArray[j])
{
int temp = numArray[j - 1];
numArray[j - 1] = numArray[j];
numArray[j] = temp;
j--;
}
else
break;
}
}
return 0;
}
选择排序
算法:将一个list分为两部分,一部分为排序完成的,另一部分为无序的,在无序中选择最小的那个与有序集合中下一个位 置的数字交换 。永远使用插入排序代替选择排序。
时间复杂度:n*nC#
代码示例
public static void SelectionSort(int[] numArray)
{
//最小元素的下标
int min;
for (int i = 0; i < numArray.Length - 1; i++)
{
//假设最小元素为第一个,开始比较判断
min = i;
//找到最小元素的下标
for (int j = i + 1; j < numArray.Length; j++)
{
if (numArray[j] < numArray[min])
{
min = j;
}
}
int temp = numArray[i];
numArray[i] = numArray[min];
numArray[min] = temp;
}
}
有效排序
归并排序
算法: 将要排序的数组不断的分成两个数组,直到每个数组只有一个元素,然后合并相邻数组C#
代码示例
//将有序数组a[]和b[]合并到c[]中
private void mergeArray(int[] a, int n, int[] b, int m, int[] c)
{
int i, j, k;
i = j = k = 0;
while (i < n && j < m)
{
if (a[i] < b[j])
c[k++] = a[i++];
else
c[k++] = b[j++];
}
while (i < n)
c[k++] = a[i++];
while (j < m)
c[k++] = b[j++];
}
//将有二个有序数列numbers[first...mid]和numbers[mid...last]合并。
private static void mainMerge(int[] numbers, int first, int mid, int last, int[] temp)
{
//两个数组的开始下标
int i = first, j = mid + 1;
//两个数组的结束下标
int m = mid, n = last;
int k = 0;
while ((i <= m) && (j <= n))
{
if (numbers[i] <= numbers[j])
temp[k++] = numbers[i++];
else
temp[k++] = numbers[j++];
}
while (i <= m)
temp[k++] = numbers[i++];
while (j <= n)
temp[k++] = numbers[j++];
for (i = 0; i < k; i++)
{
numbers[first + i] = temp[i];
}
}
public static void SortMerge(int[] numbers, int left, int right, int[] temp)
{
int mid;
if (right > left)
{
mid = (right + left) / 2;
SortMerge(numbers, left, mid, temp);
SortMerge(numbers, (mid + 1), right, temp);
mainMerge(numbers, left, mid, right, temp);
}
}
堆排序
C#
代码示例
// 新加入i结点 其父结点为(i - 1) / 2
private void MinHeapFixup(int[] a, int i)
{
int j, temp;
temp = a[i];
j = (i - 1) / 2; //父结点
//调整顺序
while (j >= 0 && i != 0)
{
//因为操纵的是最小堆,所以从插入节点的父节点开始到根节点是有序的,从大到小
//如何其父节点大于它,说明已经是有序的了,不需要在调整
if (a[j] <= temp)
break;
a[i] = a[j]; //把较大的子结点往下移动,替换它的子结点
i = j;
j = (i - 1) / 2;
}
a[i] = temp;
}
//在最小堆中加入新的数据nNum
private void MinHeapAddNumber(int[] a, int n, int nNum)
{
a[n] = nNum;
MinHeapFixup(a, n);
}
//删除节点
//从i节点开始调整,n为节点总数 从0开始计算 i节点的子节点为 2*i+1, 2*i+2
private static void MinHeapFixdown(int[] a, int i, int n)
{
int j, temp;
temp = a[i];
j = 2 * i + 1;
while (j < n)
{
if (j + 1 < n && a[j + 1] < a[j]) //在左右孩子中找最小的
j++;
if (a[j] >= temp)
break;
a[i] = a[j]; //把较小的子结点往上移动,替换它的父结点
i = j;
j = 2 * i + 1;
}
a[i] = temp;
}
//在最小堆中删除数
void MinHeapDeleteNumber(int []a, int n)
{
swap(a[0], a[n - 1]);
MinHeapFixdown(a, 0, n - 1);
}
//建立最小堆
public static void MakeMinHeap(int[] a, int n)
{
for (int i = n / 2 - 1; i >= 0; i--)
MinHeapFixdown(a, i, n);
}
public static void MinheapsortTodescendarray(int[] a, int n)
{
for (int i = n / 2 - 1; i >= 0; i--)
MinHeapFixdown(a, i, n);
for (int i = n - 1; i >= 1; i--)
{
swap(a[i], a[0]);
MinHeapFixdown(a, 0, i);
}
}
private static void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
- 快速排序
算法:分而制造之,取一元素,一般为中间元素,将小于此元素的元素放于前面,大于的放于后面对前后两部分再采取同
样的方法迭代 。
时间复杂度:nlgn
C#
代码示例
public static void QuickSort(IComparable[] elements, int left, int right)
{
int i = left, j = right;
IComparable pivot = elements[(left + right) / 2];
while (i <= j)
{
while (elements[i].CompareTo(pivot) < 0)
{
i++;
}
while (elements[j].CompareTo(pivot) > 0)
{
j--;
}
if (i <= j)
{
// Swap
IComparable tmp = elements[i];
elements[i] = elements[j];
elements[j] = tmp;
i++;
j--;
}
}
// Recursive calls
if (left < j)
{
QuickSort(elements, left, j);
}
if (i < right)
{
QuickSort(elements, i, right);
}
}
冒泡排序及其变种
- 冒泡排序
算法:从小到达排列实现:将相邻的两个值比较,如果此值较小则交换位置,当以一次冒泡后,最小值已经位于最上面了。余下的以此类推。效率低下,适合教学,实际中不要使用。
C#
代码示例
public static void BubbleSort(int[] numArray)
{
for (int i = 0; i < numArray.Length; i++)
{
for (int j = 1; j < numArray.Length-i; j++)
{
if (numArray[j-1]>numArray[j])
{
int temp = numArray[j - 1];
numArray[j - 1] = numArray[j];
numArray[j] = temp;
}
}
}
}
希尔排序
算法:分组插入排序,又叫缩小增量排序
该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况), 效率是很高的。C#
代码示例
public static void ShellSort(int[] numArray)
{
for (int gap = numArray.Length/2; gap >0; gap/=2)
{
for (int i = 0; i < gap; i++)
{
for (int j = i+gap; j < numArray.Length; j+=gap)
{
if (numArray[j]<numArray[j-gap])
{
int temp = numArray[j];
int k = j - gap;
while (k>=0&&numArray[k]>temp)
{
numArray[k + gap] = numArray[k];
k -= gap;
}
numArray[k + gap] = temp;
}
}
}
}
}
public static void ShellSortAdvaced(int[] numArray)
{
int j, gap;
for (gap = numArray.Length / 2; gap > 0; gap /= 2)
for (j = gap; j < numArray.Length; j++)//从数组第gap个元素开始
if (numArray[j] < numArray[j - gap])//每个元素与自己组内的数据进行直接插入排序
{
int temp = numArray[j];
int k = j - gap;
while (k >= 0 && numArray[k] > temp)
{
numArray[k + gap] = numArray[k];
k -= gap;
}
numArray[k + gap] = temp;
}
}
- 梳排序
算法:将整个待排序列分成若干组,每个组进行冒泡排序
C#
代码示例
public static int[] CombSort(int[] numArray)
{
double gap = numArray.Length;
bool swaps = true;
while (gap > 1 || swaps)
{
gap /= 1.247330950103979;
if (gap < 1) { gap = 1; }
int i = 0;
swaps = false;
while (i + gap < numArray.Length)
{
int igap = i + (int)gap;
if (numArray[i] > numArray[igap])
{
int swap = numArray[i];
numArray[i] = numArray[igap];
numArray[igap] = swap;
swaps = true;
}
i++;
}
}
return numArray;
}
分布排序
- 计数排序
算法:是一种稳定的排序算法。计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数, 然后根据数组C来将A中的元素排到正确的位置。
C#
代码示例
public static int[] CountingSort(int []numArray)
{
int []b = new int[numArray.Length];
int max = numArray[0], min = numArray[0];
foreach(var i in numArray)
{
if(i > max)
{
max = i;
}
if(i < min)
{
min = i;
}
}
//这里k的大小是要排序的数组中,元素大小的极值差+1
int k = max - min + 1;
int[] c = new int[k];
for(int i = 0; i < numArray.Length; ++i)
{
c[numArray[i]-min] += 1;//优化过的地方,减小了数组c的大小
}
for (int i = 1; i < c.Length; ++i)
{
c[i] = c[i] + c[i-1];
}
for (int i = numArray.Length - 1; i >= 0; --i)
{
b[--c[numArray[i]-min]] = numArray[i];//按存取的方式取出c的元素
}
return b;
}
有时间再完善相关算法的解释。