`
ak478288
  • 浏览: 73426 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

一种微缩网址的算法

阅读更多

twitter等微博客的发展带动了一批short url应用的发展,目前网上也有好几种缩短url算法。

 

下面写的是我实际使用中的一种算法。

算法简述

属于递增方式,例如

我使用的域名为abc.com

那么我存储的短网址会有

http://abc.com/aaaa

http://abc.com/aaab

http://abc.com/aaac

http://abc.com/aaad

........................


aaaa,aaab,aaac,aaad,是根据一定的规律递增短网址关键字,关键字的取值是从一个已经定义好的数组中获取。有个变量专门用来存储最后一次使用的下标,例如data=" 1,2,4,1 ",这表明上次使用的下标,当要获取新的短网址关键字的时候,从数据库或者其他存储方式中取出data的值,然后把data的值转换为数字,并进行+1操作,来获得新的可用下标,并且把新的data值保存,以便下次使用.


代码已经提供了下载,欢迎大家提意见,本人很少写blog,语言表达能力有限,有看不明白的地方,可以提出来

 

文章为原创,若转载请注明出处

 

代码

package com.hk.bean;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 由于我使用的是a-z0-9共36个字符,所以basemap中会存储36个不同字符数组<br/>
 * 也就是说,微缩后的地址最多有36位 例如最长的url为<br/>
 * http://xxx.com/abddeeddrree09869830484aaaaaderrteae<br/>
 * 但是这么长的url就失去了微缩的意义,基本用到10位还是比较合理的 使用方式请看main方法
 * 
 * @author akwei
 */
public class ShortUrlData {
	/**
	 * 预先定义要使用的字符数组,所有位置的字符都使用这里的
	 */
	private static char[] base = new char[] { 'k', '3', 'h', 'c', '0', 'p',
			'q', '6', '1', 'v', 'i', '5', 'a', 'u', 't', 'j', '4', 's', 'z',
			'd', 'o', 'w', '7', 'r', '2', 'l', 'g', 'b', 'm', 'f', 'y', '9',
			'n', '8', 'x', 'e' };

	/**
	 * 存储每个字符位置所使用的字符数组(由于每个位置的字符数组都会不同,所以通过map单独存储)<br/>
	 */
	private static final Map<Integer, char[]> basemap = new HashMap<Integer, char[]>();
	/**
	 * 此代码块的功能就是当class加载的时候,初始化basemap
	 */
	static {
		List<String> list = new ArrayList<String>();
		// 把预先定义的字符放入一个集合当中
		for (int i = 0; i < base.length; i++) {
			list.add(String.valueOf(base[i]));
		}
		// 这个for循环的作用是为了生成不同的字符数组所用
		// 实现效果例如:
		// 第一个数组为 abcdefg
		// 那么第二个数字就是bcdefga
		// 第三个就是cdefgab
		// 第四个就是defgabc
		// 第五个就是efgabcd
		// ......
		// 依次循环
		for (int i = 0; i < base.length; i++) {
			// 获取基础字符集合的前i个值,组成一个新的集合endlist
			List<String> endlist = new ArrayList<String>(list.subList(0, i));
			// 获取基础字符集合的从i到结尾的所有字符集合,组成一个新的集合reslist
			List<String> reslist = new ArrayList<String>(list.subList(i, list
					.size()));
			// 然后把endlist放入添加到reslist的末尾
			// reslist就是我们需要的其中一个字符集合
			reslist.addAll(endlist);
			// 通过StringBuffer把字符集合中的字符组成一个字符串,然后生一个一个字符数组
			StringBuffer sb = new StringBuffer();
			for (String s : reslist) {
				sb.append(s);
			}
			char[] base_i = sb.toString().toCharArray();
			// 生成的字符数组存入basemap中
			// basemap中的key-value例如
			// key:0 value:[a,b,c,d,e,f,g]
			// key:1 value:[b,c,d,e,f,g,a]
			// key:2 value:[c,d,e,f,g,a,b]
			// key:3 value:[d,e,f,g,a,b,c]
			// key:4 value:[e,f,g,a,b,c,d]
			basemap.put(i, base_i);
		}
	}

	/**
	 * 保存到数据库中的id
	 */
	private int oid;

	/**
	 * 保存到数据库中的下标字符串例如 data=" 1,4,5,6"
	 */
	private String data;

	public int getOid() {
		return oid;
	}

	public void setOid(int oid) {
		this.oid = oid;
	}

	public String getData() {
		return data;
	}

	public void setData(String data) {
		this.data = data;
	}

	/**
	 * 把data的值转化为一个int[],此int[]中存储的就是每个字符最后使用过的字符数组的下标<br/>
	 * 例如:<br/>
	 * data=1,2,4,2<br/>
	 * basemap中的key-value <br/>
	 * key:0 value:[a,b,c,d,e,f,g]<br/>
	 * key:1 value:[b,c,d,e,f,g,a]<br/>
	 * key:2 value:[c,d,e,f,g,a,b]<br/>
	 * key:3 value:[d,e,f,g,a,b,c]<br/>
	 * 那么最后一次使用的短网址关键字就是bdgf,每个字符都是与basemap中相应位置的数组对应的
	 * 
	 * @return 把data的值转化为一个int[]
	 */
	private int[] getDataList() {
		String[] s = this.data.split(",");
		int[] arr = new int[s.length];
		int i = 0;
		for (String ss : s) {
			arr[i++] = Integer.parseInt(ss);
		}
		return arr;
	}

	/**
	 * 根据最后一次的下标数组int[],计算获得一个可以使用的int[]<br/>
	 * 例如<br/>
	 * data=1,2,4,2<br/>
	 * basemap中的key-value <br/>
	 * key:0 value:[a,b,c,d,e,f,g]<br/>
	 * key:1 value:[b,c,d,e,f,g,a]<br/>
	 * key:2 value:[c,d,e,f,g,a,b]<br/>
	 * key:3 value:[d,e,f,g,a,b,c]<br/>
	 * key:4 value:[e,f,g,a,b,c,d]<br/>
	 * 通过此方法,返回 一个数字数组[1,2,4,3]<br/>
	 * 如果data=1,2,4,6<br/>
	 * 通过此方法,返回 一个数字数组[1,2,5,0]<br/>
	 * 如果data=6,6,6,6<br/>
	 * 由于4位的字符已经用完,需要升级位数到5为,返回 一个数字数组[0,0,0,0,0]<br/>
	 * 运行此方法,data的值会相应的变化
	 * 
	 * @return 返回一个可以使用的int[]下标数组
	 */
	private int[] getNextDataList() {
		// 获得最后使用的下标数组
		int[] arr = this.getDataList();
		// 此参数的意义是是否数组长度发生了变化
		boolean is_arr_length_changed = false;
		// 此循环的目的就是把获得的下标数组中从最后一位开始+1,用来获得一个可用下标数组
		// 例如 basemap中存储为
		// key:0 value:[a,b,c,d,e,f,g]<br/>
		// key:1 value:[b,c,d,e,f,g,a]<br/>
		// key:2 value:[c,d,e,f,g,a,b]<br/>
		// key:3 value:[d,e,f,g,a,b,c]<br/>
		// key:4 value:[e,f,g,a,b,c,d]<br/>
		// int[]=[1,2,4,6]
		// 经过循环后获得的就是 int[]=[1,2,5,0]
		// 例如 int[]=[1,2,3,0]
		// 经过循环后获得的就是 int[]=[1,2,3,1]
		// 例如 int[]=[6,6,6,6]
		// 经过循环后获得的就是 int[]=[0,0,0,0,0]
		for (int i = arr.length - 1; i >= 0; i--) {
			int res = this.add(i, arr[i]);
			arr[i] = res;
			if (res == 0) {
				// 如果==0,说明下标已经到了最后一位,+1后会返回0,(类似于1+9=10,结果变为2位数,需要进位)
				is_arr_length_changed = true;
				// 变为0后,前一位下标肯定要进行变化,所以继续循环,把前一位下标也+1
				continue;
			}
			// 如果>0,说明不需要进位
			if (res > 0) {
				is_arr_length_changed = false;
				break;
			}
		}
		StringBuilder sb = new StringBuilder();
		// 如果int[]数组长度没有变化,则直接给data赋值
		if (!is_arr_length_changed) {
			for (int i = 0; i < arr.length; i++) {
				sb.append(arr[i]).append(",");
			}
			sb.deleteCharAt(sb.length() - 1);
			this.data = sb.toString();
			return arr;
		}
		// 如果int[]数组长度改变了,那么就用一个新的数组,新数组的值为arr中的值,最后一位值为0
		int[] arr2 = new int[arr.length + 1];
		for (int i = 0; i < arr2.length; i++) {
			arr2[i] = 0;
			sb.append(arr2[i]).append(",");
		}
		sb.deleteCharAt(sb.length() - 1);
		this.data = sb.toString();
		return arr2;
	}

	/**
	 * 获得一个可以用的缩短后的url关键字<br/>
	 * 例如<br/>
	 * data=1,2,4,2<br/>
	 * basemap中的key-value <br/>
	 * key:0 value:[a,b,c,d,e,f,g]<br/>
	 * key:1 value:[b,c,d,e,f,g,a]<br/>
	 * key:2 value:[c,d,e,f,g,a,b]<br/>
	 * key:3 value:[d,e,f,g,a,b,c]<br/>
	 * key:4 value:[e,f,g,a,b,c,d]<br/>
	 * 通过此方法,返回 一个数字数组[1,2,4,3],通过这个数组到basemap中获得相应位置的字符,返回值为对应[1,2,4,3]的 bdgg<br/>
	 * 如果data=1,2,4,6<br/>
	 * 通过此方法,返回 一个数字数组[1,2,5,0],返回值为对应[1,2,5,0]的 bdae<br/>
	 * 如果data=6,6,6,6<br/>
	 * 由于4位的字符已经用完,需要升级位数到5为,返回 一个数字数组[0,0,0,0,0],返回值为对应[0,0,0,0,0]的 abcde<br/>
	 * 
	 * @return 返回的字符串就是我们需要的缩短url后的关键字
	 */
	public String getNextShortKey() {
		int[] arr = this.getNextDataList();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < arr.length; i++) {
			// sb.append(base[arr[i]]);
			char[] ch = basemap.get(i);
			sb.append(ch[arr[i]]);
		}
		return sb.toString();
	}

	/**
	 * 字符数组下标+1,如果到尾部,则归0 <br/>
	 * 例如<br/>
	 * basemap中的key-value <br/>
	 * key:0 value:[a,b,c,d,e,f,g]<br/>
	 * key:1 value:[b,c,d,e,f,g,a]<br/>
	 * key:2 value:[c,d,e,f,g,a,b]<br/>
	 * key:3 value:[d,e,f,g,a,b,c]<br/>
	 * key:4 value:[e,f,g,a,b,c,d]<br/>
	 * data=1,2,4,6<br/>
	 * 1对应basemap中key=0时的数组中字符b<br/>
	 * 2对应basemap中key=1时的数组中字符c<br/>
	 * 4对应basemap中key=2时的数组中字符g<br/>
	 * 6对应basemap中key=3时的数组中字符c<br/>
	 * add(0,1)=2<br/>
	 * 参数0代表1,2,4,6中的下标0<br/>
	 * 参数1代表1,2,4,6中的下标0的值1,也就是key=0时的数组[a,b,c,d,e,f,g]的下标1<br/>
	 * 返回值2代表1下标后移一位后的结果,也就是key=0时的数组[a,b,c,d,e,f,g]的下标2<br/>
	 * add(3,6)=0<br/>
	 * 返回值0代表下标已经在最后一位了,如果再次后移,就要让下标移到开始位置,也就是key:4 value:[e,f,g,a,b,c,d]中<br/>
	 * 下标6代表数组中最后一位,不能再次后移,只能回到0的位置,(简单的说就是1+9=10,个位肯定是0,需要进位)
	 * 
	 * @param digits 字符所在位数 例如 abcd c所在第2位
	 * @param i 字符数组下标
	 * @return
	 */
	private int add(int digits, int i) {
		char[] ch = basemap.get(digits);
		int res = (i + 1) % ch.length;
		return res;
	}

	public static void main(String[] args) {
		ShortUrlData o = getShortUrlDataFromDB();
		System.out.println(o.getNextShortKey());
		System.out.println(o.getData());
		// 例如从数据库取出
	}

	/**
	 * 假设是从数据库中取出
	 * 
	 * @return
	 */
	private static ShortUrlData getShortUrlDataFromDB() {
		ShortUrlData o = new ShortUrlData();
		o.setOid(1);
		o.setData("5,2,1,35");
		// o.setData("35,35,35");
		return o;
	}
}
 

 

分享到:
评论

相关推荐

    vc 游戏 小地图算法

    - **单块地图无缝延伸法**:这是一种常用的地图拼接方法,适用于初学者。关键在于地图的每个单元格(或称“块”)在上下左右边缘都有相同的图案,这样就可以无间隙地拼接成大地图。这种方法简单易懂,能够创建出...

    算法和数据结构

    比如,排序算法是组织数据的一种重要方法,其中包括快速排序、归并排序、堆排序等多种类型。每种排序算法都有其使用场景和效率特点,因此,选择合适的排序算法对于提高程序效率至关重要。 同样地,数据结构如数组、...

    电信设备-微缩二维码信息安全线及其制作方法与用途.zip

    微缩二维码作为一种创新的安全技术,已经逐渐应用于电信设备的信息保护领域。本资料详细阐述了微缩二维码信息安全线的制作方法、工作原理以及其在电信设备中的实际应用。 一、微缩二维码的概念与特点 微缩二维码是...

    图片智能微缩模块.rar

    1. **易语言**:易语言是一种以中文为编程语言的编程环境,旨在降低编程难度,使更多的人能够参与到软件开发中。在易语言图片智能微缩模块中,开发者使用易语言编写了源代码,使得模块能够运行在Windows平台上,处理...

    电信设备-一种多信息防伪标签.zip

    《电信设备-一种多信息防伪标签》是一个与电信设备安全相关的资料压缩包,其中包含了一份名为“一种多信息防伪标签.pdf”的文档。这份资料很可能详细阐述了一种创新的防伪技术,该技术可能被应用于电信设备的制造、...

    基于图像特征的人民币识别算法

    综上所述,基于图像特征的人民币识别算法是一种高效、低成本的真伪识别方案。通过精确的特征提取与合理的模型构建,该方法能够在保证较高识别率的同时,显著降低系统的复杂度和成本。未来的研究可以进一步优化特征...

    行业分类-设备装置-一种应用于标贴的图像防伪识别方法.zip

    总的来说,"一种应用于标贴的图像防伪识别方法"涵盖了图像处理技术、防伪设备、特征识别算法、机器学习以及在不同行业的应用。这种技术的发展和应用对于打击假冒商品、保护知识产权以及维护消费者权益具有深远的影响...

    行业分类-设备装置-一种基于清分机的多国纸币序列号识别方法.zip

    标题中的“行业分类-设备装置-一种基于清分机的多国纸币序列号识别方法”揭示了这个压缩包文件包含的内容主要与金融行业的设备装置有关,特别是涉及到清分机技术,以及如何通过这种设备来识别多国纸币的序列号。...

    行业文档-设计装置-一种双重防伪税票纸.zip

    本文将深入探讨“行业文档-设计装置-一种双重防伪税票纸”这一主题,旨在理解并解析这种创新的防伪技术在税票纸上的应用。 双重防伪税票纸的设计与制作是为了解决传统税票易被伪造的问题,它通常包含物理防伪和数字...

    行业文档-设计装置-一种元素防伪纸.zip

    在IT行业中,设计装置往往涉及到各种技术和应用,而“一种元素防伪纸”则可能是一种结合了技术与物理防伪手段的独特创新。这种防伪纸可能用于制作重要的文档、证书或者货币,以防止伪造和欺诈行为。下面我们将深入...

    行业分类-设备装置-一种含有单层次灰度阶梯水印的防伪纸及其制造方法.zip

    标题和描述中提到的"行业分类-设备装置-一种含有单层次灰度阶梯水印的防伪纸及其制造方法"涉及到的是信息安全领域的防伪技术,特别是应用在纸质制品中的水印技术。水印通常用于证明文件的真实性,防止伪造,尤其在...

    行业分类-设备装置-一种纸币类别识别装置.zip

    《一种纸币类别识别装置》 在金融领域和自动化服务中,纸币识别技术是不可或缺的一部分,它使得机器能够自动区分不同面额的纸币,从而实现高效、准确的交易处理。本文将深入探讨一种纸币类别识别装置的设计原理、...

    行业文档-设计装置-一种纸币或票据的鉴伪装置.zip

    这份名为“行业文档-设计装置-一种纸币或票据的鉴伪装置.zip”的压缩包文件,包含了关于设计一种纸币或票据鉴伪装置的重要知识,旨在提高金融机构、银行以及商业机构的安全性和效率。 首先,我们需要理解鉴伪装置的...

    行业分类-设备装置-一种防伪笔和防伪标记.zip

    在这个特定的案例中,我们讨论的是一种防伪笔和防伪标记的创新设计,它可能采用了先进的材料科学、光学识别技术和数字加密方法。 首先,防伪笔可能包含了特殊墨水或填充物,这种墨水在特定条件下(如紫外线照射、...

    交通网络布局问题中优化模式的改进遗传算法

    在解决此类问题时,遗传算法作为一种启发式搜索算法,被广泛应用于寻找最佳解或近似最佳解。 遗传算法是受自然选择和遗传学原理启发的优化算法,其基本思想是模拟自然界生物进化的过程。算法主要通过选择、交叉...

    行业文档-设计装置-一种书画作品的防伪方法.zip

    标题中的"一种书画作品的防伪方法"涉及到的是利用现代科技手段来防止书画作品被伪造,确保其唯一性和真实性。这篇行业文档可能详细阐述了一种创新的设计装置及其工作原理,旨在提供一个可靠的艺术品防伪解决方案。 ...

    行业分类-设备装置-一种纸币的识别方法和装置.zip

    在IT行业中,设备装置的设计与应用常常涉及到各种技术领域,其中一种重要的应用是货币识别系统。本主题聚焦于“一种纸币的识别方法和装置”,这通常是指利用现代电子技术来自动化识别不同国家和地区的纸币,以提高...

Global site tag (gtag.js) - Google Analytics