hx计算机基础

参考:http://python.jobbole.com/82294/

   https://www.jianshu.com/p/aed6067eeac9

1. 操作系统基础题

1)在32位操作系统下,系统会为每个进程预留4GB内存空间,而某机器的物理内存可能只有2GB。请解释OS是如何处理这种”矛盾”的。
  答:操作系统采用虚拟内存的方法以达到医用外存扩大内存的作用。
2)请解释进程和线程的区别 。
  答:进程:操作系统进行资源分配的基本单位。一个进程可以包含多个线程,所有线程共享进程资源。
    线程:CPU调度的基本单位。线程是轻量级的进程。它的创建和销毁比进程小的很多。
2.语法基础题:
1)请解释Python的变量作用域查找规则:
  答:局部作用域  -->函数范围作用域)-->全局作用域--->内建对象作用域
 
2)请解释Python中generator的语法行为,并说明generator的适用场合。 
  答:简单的生成器:把一个列表生成式[ ]变为( ) ,就变成一个generator。generator也是可迭代对象。
              我们可以一次性打印generator的内容,如果要一个一个打印,可以通过generator的next()方法:g.next()。这样太麻烦,一般直接通过for循环打印。
    generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
 
    带yield语句的生成器:如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。
              一般函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,                                                    再次执行时从上次返回的yield语句处继续执行。
3)请解释shallow-copy和deep-copy的区别,并用代码说明如何实现deep copy。
  答:
对象赋值:
Python中,对象的赋值都是进行对象引用(内存地址)传递

 1 will = ["Will", 28, ["Python", "C#", "JavaScript"]]
 2 wilber = will
 3 print id(will)
 4 print will
 5 print [id(ele) for ele in will]
 6 print id(wilber)
 7 print wilber
 8 print [id(ele) for ele in wilber]
 9  
10 will[0] = "Wilber"
11 will[2].append("CSS")
12 print id(will)
13 print will
14 print [id(ele) for ele in will]
15 print id(wilber)
16 print wilber
17 print [id(ele) for ele in wilber]

这里需要注意的一点是,str是不可变类型,所以当修改的时候会替换旧的对象,产生一个新的地址39758496

浅拷贝:

 1 import copy
 2  
 3 will = ["Will", 28, ["Python", "C#", "JavaScript"]]
 4 wilber = copy.copy(will)
 5  
 6 print id(will)
 7 print will
 8 print [id(ele) for ele in will]
 9 print id(wilber)
10 print wilber
11 print [id(ele) for ele in wilber]
12  
13 will[0] = "Wilber"
14 will[2].append("CSS")
15 print id(will)
16 print will
17 print [id(ele) for ele in will]
18 print id(wilber)
19 print wilber
20 print [id(ele) for ele in wilber]

浅拷贝会创建一个新的对象,这个例子中”wilber is not will”
但是,对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址),也就是说”wilber[i] is will[i]”

由于list的第一个元素是不可变类型所以will对应的list的第一个元素会使用一个新的对象39758496
但是list的第三个元素是一个可变类型,修改操作不会产生新的对象,所以will的修改结果会相应的反应到wilber上

总结一下,当我们使用下面的操作的时候,会产生浅拷贝的效果:

  • 使用切片[:]操作
  • 使用工厂函数(如list/dir/set)
  • 使用copy模块中的copy()函数
深拷贝
 1 import copy
 2  
 3 will = ["Will", 28, ["Python", "C#", "JavaScript"]]
 4 wilber = copy.deepcopy(will)
 5  
 6 print id(will)
 7 print will
 8 print [id(ele) for ele in will]
 9 print id(wilber)
10 print wilber
11 print [id(ele) for ele in wilber]
12  
13 will[0] = "Wilber"
14 will[2].append("CSS")
15 print id(will)
16 print will
17 print [id(ele) for ele in will]
18 print id(wilber)
19 print wilber

跟浅拷贝类似,深拷贝也会创建一个新的对象,这个例子中”wilber is not will”
但是,对于对象中的元素,深拷贝都会重新生成一份(有特殊情况,下面会说明),而不是简单的使用原始元素的引用(内存地址)
例子中will的第三个元素指向39737304,而wilber的第三个元素是一个全新的对象39773088,也就是说,”wilber[2] is not will[2]”
 
  • 当对will进行修改的时候

由于list的第一个元素是不可变类型,所以will对应的list的第一个元素会使用一个新的对象39758496
但是list的第三个元素是一个可不类型,修改操作不会产生新的对象,但是由于”wilber[2] is not will[2]”,所以will的修改不会影响wilber

 
 
拷贝的特殊情况:

其实,对于拷贝有一些特殊情况:

  • 对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有拷贝这一说

也就是说,对于这些类型,”obj is copy.copy(obj)” 、”obj is copy.deepcopy(obj)”

  • 如果元祖变量只包含原子类型对象,则不能深拷贝,看下面的例子

 
 

总结

本文介绍了对象的赋值和拷贝,以及它们之间的差异:

  • Python中对象的赋值都是进行对象引用(内存地址)传递
  • 使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.
  • 如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝
  • 对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有被拷贝一说
  • 如果元祖变量只包含原子类型对象,则不能深拷贝。

3. 数据结构&算法基础题(3选1)
1)请实现一个双向列表的数据结构。并实现插入。

 1 #双向链表
 2 '节点类'
 3 class Node(object):
 4     def __init__(self,data = None):
 5         self.data = data
 6         self.pre = None
 7         self.next = None
 8 
 9 
10 class Linklist(object):
11     def __init__(self):
12         self.head = None
13 
14     def is_Empty(self):
15         return self.head==None
16 
17     def length(self):
18         cur = self.head
19         count = 0
20         while cur != None:
21             count += 1
22             cur = cur.next
23         return count
24     #前面插节点
25     def add(self,item):
26         node = Node(item)
27         if self.is_Empty():
28             self.head = node
29 
30         else:
31             node.next = self.head
32             self.head.pre = node
33             self.head = node
34     #后面插节点
35     def append(self,item):
36         node = Node(item)
37         if self.is_Empty():
38             self.head = node
39 
40         else:
41             cur = self.head
42             while cur.next != None:
43                 cur = cur.next
44             cur.next = node
45             node.pre = cur
46     #查找 
47     def search(self,item):
48         node = Node(item)
49 
50         cur = self.head
51         while cur!= None:
52             if cur.data == item:
53                 return True
54             cur = cur.next
55         return False
56 
57     def insert(self,pos,item):
58         """在指定位置添加节点"""
59         if pos <= 0:
60             self.add(item)
61         elif pos > (self.length()-1):
62             self.append(item)
63         else:
64             node = Node(item)
65             cur = self.head
66             count = 0
67             while count < (pos-1) :
68                 count += 1
69                 cur = cur.next
70             node.pre = cur
71             node.next = cur.next
72             cur.next.pre = node
73             cur.next = node
74     #移除某个元素
75     def remove(self,item):
76 
77         if self.is_Empty():
78             return
79         else:
80             cur = self.head
81             if cur.item == item:        #第一个就是要找的
82                 if cur.next == None:    #只有一个头结点
83                     self.head = None
84                 else:
85                     cur.next.pre = None
86                     self.head = cur.next
87                 return
88             while cur != None:
89                 if cur.item == item:
90                     cur.pre.next = cur.next
91                     cur.next.pre = cur.pre
92                     break
93 
94                 cur = cur.next
 4)请解释同步/异步、阻塞/非阻塞这几个网络编程中的常用概念 
答:
  参考:https://www.jianshu.com/p/aed6067eeac9
 
  有人也许会把阻塞调用和同步调用等同起来,实际上它们是不同的。
  1.对于同步调用来说,很多时候当前线程可能还是激活的,只是从逻辑上当前函数没有返回而已,此时,这个线程可能也会处理其他的消息。
    (a) 如果这个线程在等待当前函数返回时,仍在执行其他消息处理,那这种情况就叫做同步非阻塞;
    b) 如果这个线程在等待当前函数返回时,没有执行其他消息处理,而是处于挂起等待状态,那这种情况就叫做同步阻塞;

       2.对于阻塞调用来说,则当前线程就会被挂起等待当前函数返回;


5. 编程应用题
 
现有1份用户访问日志,文件名为access.log,每行记录包含3列数据(' '分割):IP地址(点分格式的字符串)、URL(用户访问的URL链接)、时间戳(Unix Timestamp格式)。请实现如下数据处理需求。
备注:尽量写出可直接运行的源码,Java/C/Python均可。
1)统计该日志中所有URL的热度,并按热度降序输出TOP 5
2)统计今天凌晨3点至凌晨5点30分期间内,用户访问最频繁的5个URL(假设那段时间内的用户访问记录包含在access.log中)
3)把点分格式字符串表示的IP地址转换成其整数表示
4)如果文件太大导致单机无法直接处理,有哪些解决思路?

答:

1.

2.

3.

1 ip2num = lambda x:sum([256**j*int(i) for j,i in enumerate(x.split('.')[::-1])])
2 ip2num('192.168.0.1')
3232235521

4. 将文件分为若干个小文件

    通过一个hash函数,将URL散列到不同的文件之中,字符串映射到整型数

    通过哈希,根据余数将url分配到小文件中

  统计每一个txt文件中的URL出现的频次,存入数组中

    最后统计数组。

     
    
 
 
 
 
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/shunyu/p/8596386.html