插入排序和希尔排序执行效率的比较

现在晚上睡觉之前都会看一会讲算法的书。因为大三的时候,没有怎么好好学习过算法,而之前C/C++也一直没认真上过课,所以这次看书也像新学一样从头开始看。最先讲的算法肯定是排序算法。冒泡算法还是一看就明白了,插入也能看明白,但希尔算法看了两个晚上也没能搞明白。今天终于通过代码实现了。希尔算法也是基于插入排序算法的,但比简单的插入排序效率要高很多。当待排序数目更多时,效率高得更明显。以下是完整C源代码:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

#define NUM 1000

void insertSort(int * a, int len) {
    int i, j, t, countChange = 0;//countChange记录数据移动次数
//    int k = 0;
    for(i = 1; i < len; i++) {
        t = a[i];
        j = i-1;
        while(j >= 0 && t < a[j]) {
            a[j+1] = a[j];
            j--;
            countChange++;
        }
        a[j+1] = t;
//        k++;
//      printf("第%d次排序后的结果:", k);//显示第k次排序后的结果
//        for(j = 0; j < len; j++)
//            printf("%d ", a[j]);
//        printf("\n");
    }
    printf("完成排序一共移动数据次数:%d\n", countChange);
}

void shellSort(int * a, int len) {
    int i, j, r, t, countChange = 0;
//    int k = 0;
    for (r = len/2; r >= 1; r /= 2) {
        for (i = r; i < len; i++) {
            t = a[i];
            j = i-r;
            while (j >= 0 && t < a[j]) {
                a[j+r] = a[j];
                j -= r;
                countChange++;
            }
            a[j+r] = t;
//            k++;
//            printf("第%d排序后的结果:", k);
//            for (j = 0; j < len; j++)
//                printf("%d ", a[j]);
//            printf("\n");
        }
    }
    printf("完成排序一共移动数据次数:%d\n", countChange);
}

int main()
{
    int a[NUM], b[NUM], i;
    srand(time(NULL));//设置随机种子

    for(i = 0; i < NUM; i++)//随机生成数组数据
        a[i] = b[i] = rand();

    printf("Before sorting: ");//输出排序前的数据序列
    for(i=0; i<NUM; i++)
        printf("%d ", a[i]);

    printf("\n\n插入排序:\n");
    insertSort(a, NUM);

    printf("\n希尔排序:\n");
    shellSort(b, NUM);
    printf("\n");

    printf("After sorting: ");//输出排序后的数据序列
    for(i=0; i<NUM; i++)
        printf("%d ", a[i]);

    printf("\n");
    return 0;
}

 

去除代码注释可以查看每次排序后的结果。

当数组规模为10时,希尔排序数据移动次数只有插入排序的一半;当数组规模为100时,插入排序需要移动次数大概是希尔排序的5倍;当数组规模为100时,插入排序需要移动次数大概是希尔排序的30倍。

(原博客发布时间:2011-10-27 14:03:51)

八皇后问题,通过回溯,用Java实现

八皇后问题是:在八行八列的格子上放8个皇后(棋子),使得任意两个皇后都攻击不到对方,即使得他们都不在同一行同一列和同一斜线上。

记得以前学C语言的时候,就见过这个问题,但当时怎么都弄不懂。现在看Java的书,书上课后练习有这个题目,就上网搜了一下怎么做,现在终于差不多懂了。代码和注释如下:

public class BackTrackQueen {

	private int[] s; // 记录皇后放置情况,s[i] = w表示皇后放在第i行的第w列(从下标0开始计数)
	private int m_queenNum; // 皇后个数
	private int m_solution; // 解的个数

	public BackTrackQueen(int queenNum) {
		m_solution = 0;
		m_queenNum = queenNum;
		s = new int[queenNum];
		for (int i = 0; i < queenNum; i++) {
			s[i] = -1;
		}
	}

	/**
	 * printThis()输出解,即打印皇后的放置情况
	 */
	public void printThis() {
		System.out.println("第" + m_solution + "种解法:");
		for (int i = 0; i < m_queenNum; i++)
			System.out.println("第" + (i + 1) + "行的第" + (s[i] + 1) + "列");
	}

	/**
	 * check()判断是否满足条件; 注意,因为每个s[i]只能等于一个值,也就限定了每行只有一个皇后,
	 * 所以,不用再判断同一行是否有2个皇后。
	 * 
	 * @param n
	 * @return boolean
	 */
	public boolean check(int n) {
		for (int i = 0; i < n; i++) {
			if (s[i] == s[n]) // 判断是否存在2个皇后在同一列
				return false;
			if (Math.abs(s[n] - s[i]) == n - i)// 判断是否存在2个皇后在同一斜线上
				return false;
		}
		return true;
	}

	/**
	 * queen()核心函数,实现把所有的满足题义的情况列出来
	 * 
	 * @param n
	 */
	public void queen(int n) {
		if (m_queenNum == n) {// 如果所有皇后都放置完毕,则输出当前解
			m_solution++;
			printThis();
			return;
		} else {
			for (int i = 0; i < m_queenNum; i++) {
				s[n] = i; // 将第n个皇后放在第n行的i列,如果满足check(n)为真,则继续放置下一个皇后
				if (check(n)) // 否则i++,继续(从下标0计数,这里的第n个,其实是现实中的第n+1个)
					queen(n + 1);
			}
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		BackTrackQueen btq = new BackTrackQueen(8);//声明类的时候给定皇后个数为8,8皇后问题,也可以是N皇后问题
		btq.queen(0);
	}

}

 

参考文章:http://blog.csdn.net/lixiaoshan_18899/article/details/1286716

(原博客发布时间:2012-01-06 13:39:10)

php 实现计数排序

算法还是很重要嘀~
直接贴代码:

<?php
/*
 * count_sort.php 计数排序
 * cli 模式运行 php count_sort.php 3 4 5 6 3 2 4 56 4 3 2 8 1
 */
$a = $argv;
unset($a[0]);
$n = count($a);
// 找出数组中最大的数
$k = 0;
for ($i = 1; $i <= $n; $i++) {
	if ($k < $a[$i])
		$k = $a[$i];
}
// 初始化数组 $c
$c[0]= 0;
for ($i = 1; $i <= $k; $i++)
	$c[$i] = 0;

for ($i = 1; $i <= $n; $i++) {
	$c[$a[$i]]++;
}// 此时 $c[$i] 包含等于 $i 的元素个数

for ($i = 1; $i <= $k; $i++) {
	$c[$i] = $c[$i-1] + $c[$i];
}// 此时 $c[$i] 包含小于或等于 $i 的元素个数

for ($i = $n; $i >= 1; $i--) {
	$b[$c[$a[$i]]] = $a[$i];
	$c[$a[$i]]--;
}
// 输出已排好序的数组
for ($i = 1; $i <= $n; $i++)
	echo $b[$i] . ' ';
echo "\n";

 

今天又重新梳理了一遍,不能根据这个代码看出计数排序是稳定排序:

<?php
/** 
 * 计数排序
 */
$nums = [23,12,23,34,23,456,23,12,23,45,23,12,1234];

$n = count($nums);

// 找出数组中最大的数
$max = $nums[0];
for ($i = 1; $i < $n; $i++) {
        if ($max < $nums[$i]) {
                $max = $nums[$i];
        }
}

// 初始化用来计数的数组
for ($i = 0; $i <= $max; $i++) {
        $cnt[$i] = 0;
}

// 下面的 for loop 处理完毕后,$cnt[$i] 表示待排序数组中,值等于 $i 的元素个数
for ($i = 0; $i < $n; $i++) {
        $cnt[$nums[$i]]++;
}

// 下面的 for loop 处理完毕后,$cnt[$i] 表示待排序数组中,值小于等于 $i 的元素个数
for ($i = 1; $i <= $max; $i++) {
        $cnt[$i] = $cnt[$i-1] + $cnt[$i];
}

// 这一步比较难理解
for ($i = $n-1; $i >= 0; $i--) {
      $result[$cnt[$nums[$i]]] = $nums[$i];
      $cnt[$nums[$i]]--; // 前一个数找到位置后,那么和它值相同的数位置往前一步
}

for ($i = 1; $i < $n; $i++) {
        echo $result[$i], ' ';
}
echo PHP_EOL;