今天又是玩一天,大过年真是搞不进去学习阿 几天没写代码,今天一看竟然有一天是空缺的!
明天就去长沙了,这个年过的啊!~
到了长沙,一天的车,还是睡觉吧。
周末打了一天游戏, 太堕落了。
很久都没有写博客了,今天忽然想写,我不是工科出身,没有好的文笔,也没有艺术范儿。。。 — 可能是我感冒引起的伤感诱发出孤寂的情怀吧,哈哈
贱
没心没肺
无所谓
-有的感情是可以用时间堆起来的,有的感情世界堆不起来,我不知道我盟的友情是属于哪一种。我选择的是第一种,你呢?
-我不喜欢占别人便宜,也不愿意别人占我便宜,要选一个的话,我是会选被占便宜吧。啊··~~哈哈哈哈哈
-时间过了那么久谢谢你时不时的给我打电话,虽然不在一起共同话题已经少的可怜的~~~~~
-没怎么联系过,我也不会忘记你的~~
同学这么多,在我看来把你们当玩的最好的,一出校门深似海啊~~~
老师说的每错,学校才是最快乐的地方,我们平等,自由,没有那么多考虑
他还说出了校门后会是天壤之别······
好像我们也是这样。。。。。
现在我们的距离都可以拿着尺子在地图上量了
-屠戮 -子午 -罗汉 -剑圣 这些都是过眼云烟
现在能在一起的只有回忆了没办法,谁叫我是一个怀旧的人乃。 ### 我没有听那时候你们劝我, 还是先走了,不要问我为什么,你们知道。我也不会说:
-“一个北京广告牌都能压死一群人”这句戏言啊,我要被压死吗? 就算真的是,我的心里是说no的 -我一个人先走,就像那天空中滑落的一颗星,只有一瞬间的光辉。我能接受别人看到我座位空着很久后感慨一句 “啊XXX走了啊”。但你们不行,我当你们关系好,你们不能这样
同学?弟兄?哥们儿?朋友?手足? ### 其实我也不知道 -同学? 我们要比同学更同学 -弟兄?我们没有血缘关系 -朋友?貌似不够啊 -手足?现在我们都很少联系了也没伤残啊
我平视前方,我忘了观赏两岸的风景。 ### 我们已经很久没有聊天了。我现在已经养成了不聊天的习惯。
我高冷孤傲,我不屑浪费时间在无聊的扯淡上。 ### 上次想登一下微信扫描下二维码才发现我连微信号都忘了
我心中无一物。最高境界
我在我的路上越走越远的同时,我也离你们越来越远了 你在你们的路上越走越远的同时,也离我们越来越远了
-对我们年代的明星念念不忘,而对现在出来的那些Tfboys什么的都不屑一顾,真的是那什么 :一个年代的让说一个年代的事啊 我喜欢胡歌,刘亦菲,韩雪,何润东,赵文卓,我陪着他们慢慢变老,。我只想说一句:我还没疯狂过呢 -最喜欢听伤感的老歌,06,08年的哥我能听的精精有味(星月神话,天外飞仙一直喜欢) -我比同龄人更老。我跟不上他们的思想。
-我会忍着不看新出来的大片,别人说的再好我也对他们有抵制心里 -我喜欢看极乐或者极悲的视频 -对于感情都是只怀恋,不联系 -记得我曾对一朋友说过我有“半熟人恐遇症” 其实我是应该把“半”字去掉,可能对于聊天我也害怕把。
起因是这样的,在尝试前后端分离的这条道路上,我自己也在不断摸索,感觉要把大部分的坑都踩踩了。目前我用的技术是:
但最近写了一个项目类似知乎这样的多页网站。前端 url 的处理让我觉得不够优雅。我使用的是 hash 的方式处理动态 url 的,为此我专门在知乎上提了一个问题:前端如何处理动态url?
排序算法是非常常见也非常基础的算法,以至于大部分情况下它们都被集成到了语言的辅助库中。排序算法虽然已经可以很方便的使用,但是理解排序算法可以帮助我们找到解题的方向。
冒泡排序是最简单粗暴的排序方法之一。它的原理很简单,每次从左到右两两比较,把大的交换到后面,每次可以确保将前M个元素的最大值移动到最右边。
步骤
void bubble_sort(vector<int> &nums)
{
for (int i = 0; i < nums.size() - 1; i++) { // times
for (int j = 0; j < nums.size() - i - 1; j++) { // position
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
}
交换的那一步可以不借助temp,方法是
nums[j] += nums[j + 1];
nums[j + 1] = num[j] - nums[j + 1];
nums[j] -= num[j + 1];
复杂度分析
由于我们要重复执行n次冒泡,每次冒泡要执行n次比较(实际是1到n的等差数列,也就是(a1 + an) * n / 2
),也就是 O(n^2)
。 空间复杂度是O(n)
。
插入排序的原理是从左到右,把选出的一个数和前面的数进行比较,找到最适合它的位置放入,使前面部分有序。
步骤
void insert_sort(vector<int> &nums)
{
for (int i = 1; i < nums.size(); i++) { // position
for (int j = i; j > 0; j--) {
if (nums[j] < nums[j - 1]) {
int temp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = temp;
}
}
}
}
复杂度分析
因为要选择n次,而且插入时最坏要比较n次,所以时间复杂度同样是O(n^2)
。空间复杂度是O(n)
。
选择排序的原理是,每次都从乱序数组中找到最大(最小)值,放到当前乱序数组头部,最终使数组有序。
步骤
void selection_sort(vector<int> &nums)
{
for (int i = 0; i < nums.size(); i++) { // position
int min = i;
for (int j = i + 1; j < nums.size(); j++) {
if (nums[j] < nums[min]) {
min = j;
}
}
int temp = nums[i];
nums[i] = nums[min];
nums[min] = temp;
}
}
复杂度分析
每次要找一遍最小值,最坏情况下找n次,这样的过程要执行n次,所以时间复杂度还是O(n^2)
。空间复杂度是O(n)
。
希尔排序从名字上看不出来特点,因为它是以发明者命名的。它的另一个名字是“递减增量排序算法“。这个算法可以看作是插入排序的优化版,因为插入排序需要一位一位比较,然后放置到正确位置。为了提升比较的跨度,希尔排序将数组按照一定步长分成几个子数组进行排序,通过逐渐减短步长来完成最终排序。
例子
例如 [10, 80, 70, 100, 90, 30, 20]
如果我们按照一次减一半的步长来算, 这个数组第一次排序时以3为步长,子数组是:
10 80 70
90 30 20
100
这里其实按照列划分的4个子数组,排序后结果为
10 30 20
90 80 70
100
也就是 [10, 30 20 90 80 70 100]
然后再以1为步长生成子数组
10
30
20
..
这个时候就是一纵列了,也就是说最后一定是以一个数组来排序的。
步骤
void shell_sort(vector<int> &nums)
{
for (int gap = nums.size() >> 1; gap > 0; gap >>= 1) { // times
for (int i = gap; i < nums.size(); i++) { // position
int temp = nums[i];
int j = i - gap;
for (; j >= 0 && nums[j] > temp; j -= gap) {
nums[j + gap] = nums[j];
}
nums[j + gap] = temp;
}
}
}
复杂度分析
希尔排序的时间复杂度受步长的影响,具体分析在维基百科。
归并排序是采用分治法(Divide and Conquer)的一个典型例子。这个排序的特点是把一个数组打散成小数组,然后再把小数组拼凑再排序,直到最终数组有序。
步骤
void merge_array(vector<int> &nums, int b, int m, int e, vector<int> &temp)
{
int lb = b, rb = m, tb = b;
while (lb != m && rb != e)
if (nums[lb] < nums[rb])
temp[tb++] = nums[lb++];
else
temp[tb++] = nums[rb++];
while (lb < m)
temp[tb++] = nums[lb++];
while (rb < e)
temp[tb++] = nums[rb++];
for (int i = b;i < e; i++)
nums[i] = temp[i];
}
void merge_sort(vector<int> &nums, int b, int e, vector<int> &temp)
{
int m = (b + e) / 2;
if (m != b) {
merge_sort(nums, b, m, temp);
merge_sort(nums, m, e, temp);
merge_array(nums, b, m, e, temp);
}
}
这个实现中加了一个temp,是和原数组一样大的一个空间,用来临时存放排序后的子数组的。
复杂度分析
在merge_array
过程中,实际的操作是当前两个子数组的长度,即2m。又因为打散数组是二分的,最终循环执行数是logn
。所以这个算法最终时间复杂度是O(nlogn)
,空间复杂度是O(n)
。
快速排序也是利用分治法实现的一个排序算法。快速排序和归并排序不同,它不是一半一半的分子数组,而是选择一个基准数,把比这个数小的挪到左边,把比这个数大的移到右边。然后不断对左右两部分也执行相同步骤,直到整个数组有序。
步骤
void quick_sort(vector<int> &nums, int b, int e, vector<int> &temp)
{
int m = (b + e) / 2;
if (m != b) {
int lb = b, rb = e - 1;
for (int i = b; i < e; i++) {
if (i == m)
continue;
if (nums[i] < nums[m])
temp[lb++] = nums[i];
else
temp[rb--] = nums[i];
}
temp[lb] = nums[m];
for (int i = b; i < e; i++)
nums[i] = temp[i];
quick_sort(nums, b, lb, temp);
quick_sort(nums, lb + 1, e, temp);
}
}
解法2: 不需要辅助空间
void quick_sort(vector<int> &nums, int b, int e)
{
if (b < e - 1) {
int lb = b, rb = e - 1;
while (lb < rb) {
while (nums[rb] >= nums[b] && lb < rb)
rb--;
while (nums[lb] <= nums[b] && lb < rb)
lb++;
swap(nums[lb], nums[rb]);
}
swap(nums[b], nums[lb]);
quick_sort(nums, b, lb);
quick_sort(nums, lb + 1, e);
}
}
复杂度分析
快速排序也是一个不稳定排序,时间复杂度看维基百科。空间复杂度是O(n)
。
堆排序经常用于求一个数组中最大k个元素时。因为堆实际上是一个完全二叉树,所以用它可以用一维数组来表示。因为最大堆的第一位总为当前堆中最大值,所以每次将最大值移除后,调整堆即可获得下一个最大值,通过一遍一遍执行这个过程就可以得到前k大元素,或者使堆有序。
在了解算法之前,首先了解在一维数组中节点的下标:
步骤
void heap_sort(vector<int> &nums)
{
int n = nums.size();
for (int i = n / 2 - 1; i >= 0; i--) { // build max heap
max_heapify(nums, i, nums.size() - 1);
}
for (int i = n - 1; i > 0; i--) { // heap sort
int temp = nums[i];
num[i] = nums[0];
num[0] = temp;
max_heapify(nums, 0, i);
}
}
void max_heapify(vector<int> &nums, int beg, int end)
{
int curr = beg;
int child = curr * 2 + 1;
while (child < end) {
if (child + 1 < end && nums[child] < nums[child + 1]) {
child++;
}
if (nums[curr] < nums[child]) {
int temp = nums[curr];
nums[curr] = nums[child];
num[child] = temp;
curr = child;
child = 2 * curr + 1;
} else {
break;
}
}
}
复杂度分析
堆执行一次调整需要O(logn)
的时间,在排序过程中需要遍历所有元素执行堆调整,所以最终时间复杂度是O(nlogn)
。空间复杂度是O(n)
。
weinre官网 上有两句有意思的介绍:
weinre is WEb INspector REmote. Pronounced like the word “winery”. Or maybe like the word “weiner”. Who knows, really.
weinre is a debugger for web pages, like FireBug (for FireFox) and Web Inspector (for WebKit-based browsers), except it’s designed to work remotely, and in particular, to allow you debug web pages on a mobile device such as a phone.
往前推2到3年,前端工程师还在忧心忡忡地想,移动互联网时代下,前端是不是没有生存空间了。但今天一看,在我们团队,前端工程师超过一半的工作都是在做移动端的Web或者APP的开发。移动Web或者APP在技术本质上是和做桌面端Web没有本质区别,但是移动端的坑那是非常的多,通过学习这部分内容,让你成为一名桌面移动通吃的前端开发工程师。