最近Win32编程被编码折磨得很惨。。。记录一下两个转化函数。

wchar_t*转std::string:

std::string wchar_tToString(wchar_t *wchar){
	std::string szDst;
	wchar_t* wText = wchar;
	DWORD dwNum = WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, NULL, 0, NULL, FALSE);
	char *psText;
	psText = new char[dwNum];
	WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, psText, dwNum, NULL, FALSE);
	szDst = psText;
	delete[]psText;
	return szDst;
}

std::string转wchar_t*:

wchar_t* stringToWchar_t( std::string str){
	std::string temp = str;
	int len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)temp.c_str(), -1, NULL, 0);
	wchar_t *wszUtf8 = new wchar_t[len + 1];
	memset(wszUtf8, 0, len * 2 + 2);
	MultiByteToWideChar(CP_ACP , 0 , (LPCSTR)temp.c_str() , -1 , (LPWSTR)wszUtf8 , len);
	return wszUtf8;
}

 

最近的文件搜索项目使用到了SQLite3作为数据库来缓存本地的文件,而通过USN读取到NTFS盘上的文件(开发机器上大概40w个文件/文件夹)在Intel Core i7-6700上大概就需要7s左右的时间,而通过常规的SQLite提供的C++ API 将文件的这些信息插入到数据库的表中,大概需要30s的时间,于是开始摸索是否有办法可以提高插入的效率进而减少我们程序的后台文件搜索耗时线程所花费的时间。

慢速:直接使用SQLite的C++ API

int sqlite3_exec(  sqlite3*,    const char *sql,   int (*callback)(void*,int,char**,char**),   void *,   char **errmsg)

中速:显式开启事务

所谓”事务“就是指一组SQL命令,这些命令要么一起执行,要么都不被执行。在SQLite中,每调用一次sqlite3_exec()函数,就会隐式地开启了一个事务,如果插入一条数据,就调用该函数一次,事务就会被反复地开启、关闭,会增大IO量。如果在插入数据前显式开启事务,插入后再一起提交,则会大大提高IO效率,进而加数据快插入速度。

开启事务只需在上述代码的前后各加一句开启与提交事务的命令即可:

开启事务:

sqlite3_exec(db,"begin;",0,0,0);

提交事务:

sqlite3_exec(db,"commit;",0,0,0);

高速:关闭写同步(synchronous)

之前的速度仍然不能够接受,在有关讲解SQLite配置的资料中,看到了“写同步”选项。

在SQLite中,数据库配置的参数都由编译指示(pragma)来实现的,而其中synchronous选项有三种可选状态,分别是full、normal、off。这篇博客以及官方文档里面有详细讲到这三种参数的设置。简要说来,full写入速度最慢,但保证数据是安全的,不受断电、系统崩溃等影响,而off可以加速数据库的一些操作,但如果系统崩溃或断电,则数据库可能会损毁。

SQLite3中,该选项的默认值就是full,如果我们再插入数据前将其改为off,则会提高效率。如果仅仅将SQLite当做一种临时数据库的话,完全没必要设置为full。在代码中,设置方法就是在打开数据库之后,直接插入以下语句:

sqlite3_exec(db,"PRAGMA synchronous = OFF; ",0,0,0);

极速:

虽然写同步设为off后,速度又有小幅提升,但是仍然较慢。我又一次踏上了寻找提高SQLite插入效率方法的道路上。终于,我发现,SQLite执行SQL语句的时候,有两种方式:一种是使用前文提到的函数sqlite3_exec(),该函数直接调用包含SQL语句的字符串;另一种方法就是“执行准备”(类似于存储过程)操作,即先将SQL语句编译好,然后再一步一步(或一行一行)地执行。如果采用前者的话,就算开起了事务,SQLite仍然要对循环中每一句SQL语句进行“词法分析”和“语法分析”,这对于同时插入大量数据的操作来说,简直就是浪费时间。因此,要进一步提高插入效率的话,就应该使用后者。

“执行准备”主要分为三大步骤:

  1. 调用函数sqlite3_prepare_v2(),并且声明一个指向sqlite3_stmt对象的指针,该函数对参数化的SQL语句zSql进行编译,将编译后的状态存入ppStmt中。
  2. 调用函数 sqlite3_step(),这个函数就是执行一步(本例中就是插入一行),如果函数返回的是SQLite_ROW则说明仍在继续执行,否则则说明已经执行完所有操作。
  3. 调用函数 sqlite3_finalize(),关闭语句。
  4. 样例代码如下:
    int _tmain(int argc, _TCHAR* argv[])
    {
    	const int nCount = 500000;
    	sqlite3* db;
    	sqlite3_open("testdb.db", &db);
    	sqlite3_exec(db, "PRAGMA synchronous = OFF; ", 0, 0, 0);
    	sqlite3_exec(db, "drop table if exists t1", 0, 0, 0);
    	sqlite3_exec(db, "create table t1(id integer,x integer,y integer ,weight real)", 0, 0, 0);
    	clock_t t1 = clock();
    
    	sqlite3_exec(db, "begin;", 0, 0, 0);
    	sqlite3_stmt *stmt;
    	const char* sql = "insert into t1 values(?,?,?,?)";
    	sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, 0);
    
    	for (int i = 0; i<nCount; ++i)
    	{
    		sqlite3_reset(stmt);
    		sqlite3_bind_int(stmt, 1, i);//bind第一个数据
    		sqlite3_bind_int(stmt, 2, i * 2);//bind第二个数据
    		sqlite3_bind_int(stmt, 3, i / 2);//bind第三个数据
    		sqlite3_bind_double(stmt, 4, i*i);//bind第四个数据
    		sqlite3_step(stmt);
    	}
    	sqlite3_finalize(stmt);
    	sqlite3_exec(db, "commit;", 0, 0, 0);
    	clock_t t2 = clock();
    	sqlite3_close(db);
    	std::cout << "cost time: " << (t2 - t1) / 1000. << "s" << std::endl;
    
    	system("pause");
    	return 0;
    }

     

综上所述啊,SQLite插入数据效率最快的方式就是:事务+关闭写同步+执行准备(存储过程),如果对数据库安全性有要求的话,就开启写同步。

在Win32中调试程序时经常需要输出调试信息以追踪数据流及程序运行状态。

当然,我们可以通过输出日志、文件等方式得到信息,但是控制台或许更方便、直观。

之前在使用基于Win32的ACLlib进行开发的时候,一直都可以显示一个控制台(也可以隐藏),感觉很方便。

那么,如何方便地在带GUI的Win32程序中,比如基于Duilib的Win32GUI程序中使用控制台进行调试输出?

具体操作流程如下:

  1. 打开控制台
  2. 重定向输出流至控制台
  3. 执行调试信息输出操作.

完整代码如下:

AllocConsole();
freopen("CONOUT$", "w", stdout);
std::cout << "This is a test info" << std::endl;

 

相关函数说明:

AllocConsole函数的功能是为当前的窗口程序申请一个Console窗口,其原型为

BOOL AllocConsole(void);

 

函数调用成功,返回非零值,调用不成功则返回0。

freopen函数用来替换一个流,或者说重新分配文件指针,以实现重定向。可重定向的流有:标准输入流、标准输出流或者标准错误流。其函数原型为

FILE *freopen(const char *path, const char *mode, FILE *stream);

其中”CONOUT$”是指代当前console的特殊字符串,”w”表明以written模式打开这个console,stdout指代标准输出流。

 

补充:

AllocConsole函数不能改变控制台窗口在屏幕上的位置、尺寸等属性。以下函数可以控制&获取控制台相关信息。

GetConsoleScreenBufferInfo   // 检索窗口大小,屏幕缓冲区大小及颜色属性
SetConsoleWindowInfo       // 改变控制台窗口大小
SetConsoleScreenBufferSize   // 改变控制台屏幕缓冲区大小
SetConsoleTextAttribute      // 设置颜色属性
SetConsoleTitle          // 设置控制台窗口标题
GetConsoleTitle          // 获取控制台窗口标题

临界区

一个临界区就是一段不会被中断的代码。

使用临界区共有四个函数。为了使用这些函数,你必须定义一个临界区对象,这个对象是一个类型为CRITICAL_SECTION的全部变量。比如,

CRITICAL_SECTION cs;

这个CRITICAL_SECTION数据类型是一个结构,但它的字段只被Windows内部使用。这个变量必须首先被程序中的一个线程通过如下方式初始化:

InitializeCriticalSection(&cs);

这创立了一个叫cs的临界区对象。这个函数的文档包括以下警告:“临界区对象不能被移动或复制。程序不可以修改它,并且必须把它当作不透明的对象。”说白了,这可以被理解为“不要改动或甚至读取它。”

在临界区对象被初始化后,一个线程通过调用以下函数来进入临界区:

EnterCriticalSection(&cs);

这时,我们就说这个线程拥有这个临界区对象。两个线程不能同时拥有同一个临界区。所以,如果一个线程进入了临界区,那么下一个线程在调用EnterCriticalSection来进入同一个临界区对象时会被挂起。这个函数直到第一个线程调用以下函数离开临界区时才会返回:

LeaveCriticalSection(&cs);

在这时,由于调用EnterCriticalSection而被挂起的第二个线程会拥有这个临界区,而且函数调用会返回,使得线程可以继续。

当程序不再需要临界区对象时,可以通过以下函数删除它:

DeleteCriticalSection(&cs);

这会释放为了维护临界区对象而分配的所有系统资源。

UTF8转Unicode:

char* UTF8ToUnicode(char* szUTF8)
{
    int wcscLen = ::MultiByteToWideChar(CP_UTF8, NULL, szUTF8, int(strlen(szUTF8)), NULL, 0);//得到所需空间的大小
    wchar_t* wszcString = new wchar_t[wcscLen + 1];//给'\0'分配空间
    ::MultiByteToWideChar(CP_UTF8, NULL,szUTF8, int(strlen(szUTF8)), wszcString, wcscLen);   //转换
    wszcString[wcscLen] = '\0';
    char *m_char;
    int len = WideCharToMultiByte(CP_ACP, 0, wszcString, int(wcslen(wszcString)), NULL, 0, NULL, NULL);
    m_char = new char[len + 1];
    WideCharToMultiByte(CP_ACP, 0, wszcString, int(wcslen(wszcString)), m_char, len, NULL, NULL);
    m_char[len] = '\0';
    return m_char;
}

 

Unicode转UTF-8:

char* UnicodeToUTF8(wchar_t* wszcString)
{
    int utf8Len = ::WideCharToMultiByte(CP_UTF8, NULL, wszcString, int(wcslen(wszcString)), NULL, 0, NULL, NULL);    //得到所需空间的大小
    char* szUTF8 = new char[utf8Len + 1];    //给'\0'分配空间
    ::WideCharToMultiByte(CP_UTF8, NULL, wszcString, int(wcslen(wszcString)), szUTF8, utf8Len, NULL, NULL);    //转换
    szUTF8[utf8Len] = '\0';
    return szUTF8;
}

 

ANSI转Unicode:

wchar_t* ANSIToUnicode(char *szAnsi)
{
    // ansi to unicode
    //预转换,得到所需空间的大小
    int wcsLen = ::MultiByteToWideChar(CP_ACP, NULL, szAnsi, strlen(szAnsi), NULL, 0);
    //分配空间要给'\0'留个空间,MultiByteToWideChar不会给'\0'空间
    wchar_t* wszString = new wchar_t[wcsLen + 1];
    //转换
    ::MultiByteToWideChar(CP_ACP, NULL, szAnsi, strlen(szAnsi), wszString, wcsLen);
    //最后加上'\0'
    wszString[wcsLen] = '\0';
	return wszString;
}

 

Unicode转Ansi:

char* UnicodeToANSI(wchar_t* wszString)
{
     // unicode to ansi
    //预转换,得到所需空间的大小,这次用的函数和上面名字相反
    int ansiLen = ::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), NULL, 0, NULL, NULL);
    //同上,分配空间要给'\0'留个空间
    char* szAnsi = new char[ansiLen + 1];
    //转换
    //unicode版对应的strlen是wcslen
    ::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), szAnsi, ansiLen, NULL, NULL);
    //最后加上'\0'
    szAnsi[ansiLen] = '\0';
	return szAnsi;
}

 

    def func(b):
        return a+b

这称为一个闭包,闭包函数比普通函数会多出一个__closure__属性,里面定义了一个元组用于存放所有的cell对象,每个cell对象一一保存了这个闭包中所有的外部变量,所有我们只需要修改其中对应的cell对象的值就好了。

完整代码如下:

# -*- coding: utf-8 -*-
def makefunc(a):
    def func(b):
        return a+b
    return func

f = makefunc(1)
f.__closure__[0].cell_contents = 2
print(f(1))
print(f(2))

输出成功的变为:

3
4

 

 

使用了Win32 API中的GetVolumeInformation函数:MSDN

#include<stdio.h>
#include<iostream>
#include<windows.h>
#include <stdarg.h>//可变参数使用所需头文件
using namespace std;
int main()
{
    LPCSTR path = "D:/";
    char sysNameBuf[MAX_PATH] = {0};
    int status = GetVolumeInformationA(path,
                                       NULL, // 驱动盘名缓冲,这里我们不需要
                                       0,
                                       NULL,
                                       NULL,
                                       NULL,
                                       sysNameBuf, // 驱动盘的系统名( FAT/NTFS)
                                       MAX_PATH);

    if (0!=status)
    {
        printf("盘符:%s\n文件系统名 : %s\n", path,sysNameBuf);
        // 比较字符串
    }
}

其中path为驱动盘的根路径,后面要加一个斜杠。

sysNameBuf接收文件系统名称的缓冲区的指针,例如FAT文件系统或NTFS文件系统。

 

Python的每个对象都分为可变和不可变,主要的核心类型中,数字、字符串、元组是不可变的,列表、字典是可变的。

不可变类型以int类型为例:

让我们看看如下代码:

i = 5
i = i + 1

实际上 i = i + 1 并不是真的在原有的int对象上+1,而是重新创建一个值为6的int对象,i引用自这个新的对象。

为了验证这一点,我们通过id函数查看变量i的内存地址进行验证(使用hex(id(i)) 可以查看16进制的内存地址)

可以看到执行 i += 1 时,内存地址都会变化,因为int 类型是不可变的。

再改改代码,但多个int类型的变量值相同时,看看它们内存地址是否相同。

对于不可变类型int,无论创建多少个不可变类型,只要值相同,都指向同个内存地址,同样情况的还有比较短的字符串。

而对于其他类型则不同,以浮点类型为例,从代码运行结果可以看出它是个不可变类型:对i的值进行修改后,它指向新的内存地址。

但如果修改代码声明两个相同值的浮点型变量,查看它们的id,会发现它们并不是指向同个内存地址,这点和int类型不同(这方面涉及Python内存管理机制,Python对int类型和较短的字符串进行了缓存,无论声明多少个值相同的变量,实际上都指向同个内存地址)

 

可变类型以List类型为例:

List在append之后,还是会指向同个内存地址,因为list是可变类型,可以在原处修改。

改改代码,当存在多个值相同的不可变类型变量时,看看它们是不是跟可变类型一样指向同个内存地址。答案是否定的,虽然a、b的值相同,但是指向的内存地址不同。我们也可以通过b = a 的赋值语句,让他们指向同个内存地址。

这个时候需要注意,因为a、b指向同个内存地址,而a、b的类型都是List,可变类型,对a、b任意一个List进行修改,都会影响另外一个List的值。

其中1-30题采用Python2.7,31-36题采用Python3.7

(1)有1、2、3、4四个数字,能组成哪些互不相同且无重复数字的三位数?

# -*- coding: utf-8 -*-
for i in range(1,5):
    for j in range(1,5):
        for k in range(1,5):
            num = i*100+j*10+k;
            if(i!=j & j!=k):
                print num

 

(2)企业发放的奖金根据利润提成。利润(i)低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;20万到40万之间时,高于20万元的部分,可提成5%;40万到60万之间时高于40万元的部分,可提成3%;60万到100万之间时,高于60万元的部分,可提成1.5%,高于100万元时,超过100万元的部分按1%提成,求当利润为i时应发放奖金总数。

# -*- coding: utf-8 -*-
num = input()
sum = 0
if(num <= 100000):
    sum = sum + num * 0.1
if(num > 100000 & num <= 200000):
    sum = sum + 100000 * 0.1 + (num-100000) * 0.075
if(num > 200000 & num <= 400000):
    sum = sum + 100000 * 0.1 + 100000 * 0.075 + (num - 200000) * 0.05
if(num >400000 & num <= 600000):
    sum = sum + 100000 * 0.1 + 100000 * 0.075 + 200000 * 0.05 + (num - 400000) * 0.03
if(num > 600000 & num <=1000000):
    sum = sum + 100000 * 0.1 + 100000 * 0.075 + 200000 * 0.05 + 200000 * 0.03 + (num - 600000) * 0.015
if(num > 1000000):
    sum = sum + 100000 * 0.1 + 100000 * 0.075 + 200000 * 0.05 + 200000 * 0.03 + 400000 * 0.015 + (num - 1000000) * 0.01
print sum

 

(3)输入某年某月某日,判断这一天是这一年的第几天?

# -*- coding: utf-8 -*-
 
def leapyear(year):
    return ((year % 400 == 0) | (year % 4 == 0 & year % 100 != 0))
 
sum = 0
year = input("请输入年:")
month = input("请输入月:")
day = input("请输入日:")
if(month > 1):
    sum = sum + 31
if(month > 2):
    if(leapyear(year)):
        sum = sum + 29
    else:
        sum = sum + 28
if(month > 3):
    sum = sum + 31
if(month > 4):
    sum = sum + 30
if(month > 5):
    sum = sum + 31
if(month > 6):
    sum = sum + 30
if(month > 7):
    sum = sum + 31
if(month > 8):
    sum = sum + 31
if(month > 9):
    sum = sum + 30
if(month > 10):
    sum = sum + 31
if(month > 11):
    sum = sum + 30
 
sum = sum + day
print ("第%d天" %(sum))

 

(4)使用□■输出国际象棋棋盘(8*8)。

# -*- coding: utf-8 -*-
 
for i in range(1,9):
    for j in range(1,9):
        if((i+j)%2 == 0):
            print("□"),
        else:
            print("■"),
    print("")

 

(5)有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第N个月的兔子总数为多少?

# -*- coding: utf-8 -*-
num = input()
a = 1
b = 1
 
def fun(num):
    if(num == 1):
        return 1
    elif(num == 2):
        return 1
    else:
        return fun(num - 1) + fun(num - 2)
print 2*fun(num)

 

(6)将一个正整数分解质因数。例如:输入90,打印出90=2*3*3*5。

# -*- coding: utf-8 -*-
num = input()
print(num),
print("="),
for i in range(2,num):
    if(num == 1):
        break;
    while(num % i == 0):
        print(i),
        num = num / i;
        if(num != 1):
            print("*"),

 

(7)输入一个字符串,分别统计出其中英文字母、空格、数字和其它字符的个数。

# -*- coding: utf-8 -*-
str = raw_input()
alpha = 0
space = 0
number = 0
other = 0
for i in str:
    if(i.isalpha()):
        alpha=alpha + 1
    elif(i.isdigit()):
        number = number + 1
    elif(i.isspace()):
        space = space + 1
    else:
        other = other + 1
print("英文字母数=%d"%alpha)
print("数字数=%d"%number)
print("空格数=%d"%space)
print("其他字符数=%d"%other)

 

(8)输入a,n(0<a<10, 0<n<10),求s=a+aa+aaa+aaaa+aa…a(n个a)的值。例如a=2,n=5时为:2+22+222+2222+22222。

# -*- coding: utf-8 -*-
a = input()
n = input()
 
sum = 0
for i in range(n,0,-1):
    sum = sum + i * a
    a = a * 10
print sum

 

(9) 一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在第10次落地时,共经过多少米?第10次反弹多高?

# -*- coding: utf-8 -*-
num = 100.0
sum = 100.0
for i in range(0,9):
    num = num / 2.0
    sum = sum + num * 2.0
print ("第十次:%f"%(num/2.0))
print ("总距离:%f"%sum)

 

(10) 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少?

# -*- coding: utf-8 -*-
num= 1
for i in range(0,9):
    num= (num + 1)*2
print num

 

(11) 两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单。

# -*- coding: utf-8 -*-
def fun(num):
    if num == 0:
        return "X"
    if num == 1:
        return "Y"
    if num == 2:
        return "Z"
 
for i in range(0,3):
    for j in range(0,3):
        if(i != j):
            for k in range(0,3):
                if(i != k and j != k):
                    if(k != 0 and i != 0 and k != 2):
                        print "A vs",
                        print fun(i)
                        print "B vs",
                        print fun(j)
                        print "C vs",
                        print fun(k)

 

(12) 求1+2!+3!+…+20!的和。

# -*- coding: utf-8 -*-
def fun(num):
    if(num == 1):
        return 1
    else:
        return num * fun(num-1)
 
sum = 0
for i in range(1,21):
    sum = sum + fun(i)
 
print sum

 

(13) 给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。

# -*- coding: utf-8 -*-
 
def printConverse(num):
    count = 0
    while(num != 0):
        temp = num % 10
        print temp,
        num = num/10
        count = count + 1
    return count
 
num = input()
print num,
print "逆序输出:",
a = printConverse(num)
print "位数为:",
print a

 

(14)有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13…求出这个数列的前20项之和,用分数形式表现出来。

(1)使用fractions库函数实现

# -*- coding: utf-8 -*-
import fractions
from fractions import  Fraction
a = 2
b = 1
sum = 0
for i in range(0,20):
    sum = sum + Fraction(a,b)
    temp = a
    a = a + b
    b = temp
 
print sum

(2)不用fractions库函数实现

# -*- coding: utf-8 -*-
a = 1
b = 2
denominator = 1
denominator = denominator * a * b
arrayDen = [1,2]
arrayNum = [2]
for i in range(0,18):
    sum = a + b
    arrayDen.append(sum)
    a = b
    b = sum
    denominator = denominator * sum
    arrayNum.append(sum)
 
arrayNum.append(a+b)
 
sumDen = denominator
sumNum = 0
for i in range(0,20):
    sumNum = sumNum + sumDen/arrayDen[i]*arrayNum[i]
 
for i in range(0,20):
    if(sumDen % arrayDen[i] == 0 and sumNum % arrayDen[i] == 0):
        sumDen = sumDen / arrayDen[i]
        sumNum = sumNum / arrayDen[i]
    if(sumDen % (i+1) == 0 and sumNum % (i+1) ==0):
        sumDen = sumDen/(i+1)
        sumNum = sumNum/(i+1)
print sumNum,
print "/",
print sumDen

 

(15)求0—7所能组成的数字中,不重复的8位奇数的个数。

# -*- coding: utf-8 -*-
sum = 1
#从1,3,5,7中选择奇数作为末尾
sum = sum * 4
#选择非0首位
sum = sum * 7
for i in range(6,0,-1):
    sum = sum * i
print sum

 

(16)已有结论“一个偶数总能表示为两个素数之和”,试输入一个偶数,用代码求出它对应的两个素数,若不止一组,尝试求相差最小的一组,比如16=13+3=11+5,则11+5更符合要求。

# -*- coding: utf-8 -*-
def isPrime(num):
    for i in range(2,num):
        if num % i == 0:
            return False
    return True
 
num = input()
temp = num / 2
for i in range(0,temp):
    if( isPrime( temp + i ) and isPrime( temp - i )):
        print temp+i,temp-i
        break;

 

(17) 对一个列表元素进行排序,要求:非冒泡排序法,非内置排序函数。

# -*- coding: utf-8 -*-
 
array = [1,5,5,6,3,6,2,7,9,1,0]
def selectionSort(arr):
    for i in range(0,len(arr)):
        min = i;
        for j in range(i+1,len(arr)):
            if(arr[j] < arr[min]):
                min = j
        if i != min:
            arr[min],arr[i] = arr[i],arr[min]
    return arr
 
print selectionSort(array)

 

(18) 有一个已经排好序的列表。现输入一个数,要求按原来的规律将它插入数组中。(注意,并不知列表原来是什么顺序)

# -*- coding: utf-8 -*-
 
array = [9,5,3,2,1]
 
num = input()
def insertArray(array , num):
    if(len(array) == 0 or len(array) == 1):
        array.append(num)
    else:
        if(array[0] < array[len(array)-1]):
            #升序
            for i in range(0,len(array)-1):
                if(num <= array[0]):
                    array.insert(0,num)
                    break
                elif(num >= array[len(array)-1]):
                    array.append(num)
                    break
                elif(array[i]<num and array[i+1]>=num):
                    array.insert(i+1,num)
        else:
            #降序
            for i in range(0,len(array)-1):
                if (num >= array[0]):
                    array.insert(0, num)
                    break
                elif (num <= array[len(array) - 1]):
                    array.append(num)
                    break
                elif (array[i] > num and array[i + 1] <= num):
                    array.insert(i + 1, num)
 
insertArray(array,num)
print array

 

(19) 一个列表逆序输出。(注意仅逆序输出,不要改变原列表元素)

# -*- coding: utf-8 -*-
 
array = [9,5,3,2,1]
 
for i in range(len(array)-1,-1,-1):
    print array[i],

 

(20) 将一个整数依次按 十六进制、八进制、二进制输出。

# -*- coding: utf-8 -*-
num = input()
print hex(num)
print oct(num)
print bin(num)

 

(21)  写如下几个进制转换函数,实现八进制、十进制、十六进制字符串的互转,不能使用内建转换函数,dec2oct,dec2hex,oct2dec,oct2hex,hex2oct,hex2dec,比如hex2oct(“FF”)==dec2oct(“255”)==”377″。

 

(22)输入整数V和整数m,n(0<=m<n<=31,0是低位),取V的二进制的第m到n位数字。例如:输入52,二进制为:0011 0100,取第3到5位的结果为:011。

# -*- coding: utf-8 -*-
V = input()
m = input()
n = input()
 
a =  str(bin(V))
print a
for i in range(m,n+1):
    print a[len(a)-1-i],

 

(23) 输入一个列表,将列表中最大的数与第一个元素交换,最小的与最后一个元素交换,输出之。

# -*- coding: utf-8 -*-
array = [7,1,5,6,6,2,1,4,8,9,5]
max = 0
min = 0
for i in range(0,len(array)):
    if(array[i] > array[max]):
        max = i
    if(array[i] < array[min]):
        min = i
 
array[max],array[0] = array[0],array[max]
array[min],array[len(array)-1] = array[len(array)-1],array[min]
 
print array

 

(24) 有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。

# -*- coding: utf-8 -*-
n = input()
array = []
count = 0
for i in range(1,n+1):
    array.append(i)
 
while(len(array) > 1):
    q = []
    for i in array:
        count = count + 1
        if(count % 3 != 0):
            q.append(i)
    array = q
 
print  array[0]

 

(25) 创建一个列表,依次输入整形元素并插入列表尾;

(1)反向输出之,

(2)输出其单数列的元素,再输出其双数列的元素

(3)让单数列元素按升序排列,双数列元素按降序排列

# -*- coding: utf-8 -*-
n = input()
array = []
for i in range(0,n):
    temp = input()
    array.append(temp)
 
for i in range(n-1,-1,-1):
    print array[i],
 
print
 
for i in range(0,n):
    if(i % 2 == 0):
        print array[i],
print
 
for i in range(0,n):
    if(i % 2 == 1):
        print array[i],
print
 
for i in range(2,n,2):
    for j in range(i+1,n,2):
        if(array[j] > array[j-2]):
            array[j],array[j-2] = array[j-2],array[j]
 
for i in range(1,n,2):
    for j in range(i+1,n,2):
        if(array[j] < array[j-2]):
            array[j],array[j-2] = array[j-2],array[j]
 
print array

 

(26)创建一个字典,依次输入整形键、值并放入字典中。

1)依次打印键、值

2)以键的升序打印值

3)以值的升序打印键,同值则以键序

4)删除字典中键为1的元素,删除字典中值为1的元素

5)遍历字典,将字典中键为单数的元素都删去

# -*- coding: utf-8 -*-
dict = {}
a = []
b = []
for i in range(0,3):
    a = input()
    b = input()
    dict[a]=b
 
for key in dict.keys():
    print key,dict[key]
 
#以键排序
a = sorted(dict.items(),key = lambda  e:e[0],reverse=False)
#以值排序
b = sorted(dict.items(),key = lambda  e:e[1],reverse=False)
print a
print b
 
#删除字典中键为1的元素
for key in dict.keys():
    if(key == 1):
        dict.pop(1)
 
#删除字典中值为1的元素
for key in dict.keys():
    if(dict[key] == 1):
        dict.pop(key)
 
#普通遍历将字典中键为单数的元素都删去
count = 0
for key in dict.keys():
    if(count % 2 == 0):
        dict.pop(key)
    count = count + 1
 
print dict

 

(27) 编写一个类CPeople,保存着人的姓名str、年龄int、性别bool、工号int;依次从键盘或者文件输入每个人的如上信息。

1)遍历输出所有人的信息,格式为:“姓名:xxx;年龄:xx;性别:男/女;工号:xxxxxx”

2)遍历输出所有男性/女性员工信息,注意列对齐

3)按年龄升序输出所有员工姓名,同年龄则以工号升序为序

4)存储people类对象的数据结构使用list/dict,重新实现上述需求

# -*- coding: utf-8 -*-
class CPeople(object):
 
    def __init__(self , name , age , gender ,number):
        self.name = name
        self.age = age
        self.gender = gender
        self.number = number
 
liu = CPeople("liu",20,True,101)
chen = CPeople("chen",20,True,102)
deng = CPeople("deng",21,True,104)
yang = CPeople("yang",21,True,103)
tian = CPeople("tian",20,True,105)
xia = CPeople("xia",20,False,106)
 
arr = [liu,chen,yang,deng,tian,xia]
for i in arr:
    print i.name,i.age,i.gender,i.number
 
#输出男性
print "BOY:"
for i in arr:
    if(i.gender):
        print i.name,i.age,i.gender,i.number
 
#输出女性
print "GIRL:"
for i in arr:
    if(i.gender == False):
        print i.name,i.age,i.gender,i.number
 
#按年龄升序输出所有员工姓名,同年龄则以工号升序为序
try:
    import  operator
except ImportError:
    cmpfun = lambda CPeople:CPeople.age
else:
    cmpfun = operator.attrgetter("age","number")
 
    arr.sort(key = cmpfun , reverse = False)
    for i in arr:
        print  i.name

 

(28) 某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:

每位数字都加上5,然后用和除以10的余数代替该数字,再将第一位和第四位交换,第二位和第三位交换。

写出其加密、解密函数。

# -*- coding: utf-8 -*-
data = 1007
#加密函数
def encryptionFun(num):
    num1 = num/1000
    num2 = num/100 % 10
    num3 = num/10 %10
    num4 = num % 10
    num1 = (num1 + 5) % 10
    num2 = (num2 + 5) % 10
    num3 = (num3 + 5) % 10
    num4 = (num4 + 5) % 10
    num1,num4 = num4,num1
    num2,num3 = num3,num2
    return num1*1000+num2*100+num3*10+num4
 
#解密函数
def decodeFun(num):
    num1 = num / 1000
    num2 = num / 100 % 10
    num3 = num / 10 % 10
    num4 = num % 10
    num1, num4 = num4, num1
    num2, num3 = num3, num2
    num1 = (num1 + 10 - 5)%10
    num2 = (num2 + 10 - 5)%10
    num3 = (num3 + 10 - 5)%10
    num4 = (num4 + 10 - 5)%10
    return num1*1000+num2*100+num3*10+num4
 
 
print encryptionFun(data)
print decodeFun(encryptionFun(data))

 

(29) 输入一个字符串,一个子串,计算字符串中子串出现的次数,已匹配过的字符不能再算做下一次匹配字符中。例如”abababab”, “abab” -> 2。

# -*- coding: utf-8 -*-
str= "abababab"
substr = "abab"
 
count = 0
i = 0
while(i <= len(str)-1):
    if(str.find(substr, i, len(str) ) != -1):
        count = count + 1
        i = i + len(substr)
    else:
        i = i + 1
print count

 

(30) 输入一个字符串,出现频率最高的3个字。

# -*- coding: utf-8 -*-
text ="系统初始为Win7.64bit系统,每个项目有特定的操作系统环境需求,具体请咨询所属项目同事;如需调整默认启动系统,请在Win7系统下进行如下操作(必须在Win7系统下才能设置):计算机(右键)-属性-高级系统设置-高级-启动和故障恢复(设置)-默认操作系统"
dict = {}
for word in text:
    if word not in dict:
        dict[word] = 1
    else:
        dict[word] = dict[word] + 1
b = sorted(dict.items(),key = lambda  e:e[1],reverse=True)
print(b)

 

(31) lst = [8,5,0,2,4,6,9,1,3,7],输入一个由0~9组成的列表,将其排序,要求lst位置靠前的元素,其排序后位置同样靠前。

# -*- coding: utf-8 -*-
lst = [8,5,0,2,4,6,9,1,3,7]
list = [0,1,2,3,4,5,6,7,8,9]
dict = {}
count = 0
for i in lst:
    dict[i] = count
    count = count + 1
 
for i in range(0,len(list)):
    for j in range(1,len(list)):
        if(dict[list[j]]<dict[list[j-1]]):
            list[j],list[j-1] = list[j-1],list[j]
 
print (list)

 

(32)在键盘上,左手每隔2秒按下一个字母键,依次循环按下A-Z,右手每隔5秒按下一个数字键,依次循环按下0-9,写代码模拟求按下的第100个键,是那个手?按下的哪个键?

# -*- coding: utf-8 -*-
a = 'A'
b = '1'
count = 0
second = 0
press = ''
 
while(True):
    if(second % 2 == 0):
        press = a
        a = chr(ord(a)+1)
        count = count + 1
 
    if(second % 5 == 0):
        press = b
        b = chr(ord(b)+1)
        count = count + 1
 
    second = second + 1
 
    if(count == 100):
        break
 
print(press,end="")
print("键")
if(press > 'A' and press < 'Z'):
    print("左手")
else:
    print("右手")

 

(33)有如下字典,记录每个地图场景能去往哪个地图场景

DATA = {

“中州城”   : (“师道殿”, “云梦泽”, “逐风原”, “清水湾”, “千魂塔一层”, “帮派地图”, ),

“北漠城”   : (“鸣沙洲”, “百花谷”, ),

“月牙湾”   : (“云梦泽”, “伏波港”, ),

“伏波港”   : (“月牙湾”, “百花谷”, ),

“鸣沙洲”   : (“北漠城”, “苍茫山”, ),

“逐风原”   : (“平安镇”, “中州城”, ),

“百花谷”   : (“北漠城”, “伏波港”, ),

“千魂塔一层”  : (“千魂塔二层”, “中州城”, ),

“云梦泽”   : (“月牙湾”, “中州城”, ),

“苍茫山”   : (“鸣沙洲”, ),

“清水湾”   : (“中州城”, “平安镇”, ),

“师道殿”   : (“绝情谷”, “真武门”, “蛮王殿”, “中州城”, “药王宗”, “天策府”, “拜火教”, “清虚观”, ),

“清虚观”   : (“师道殿”, ),

“天策府”   : (“师道殿”, ),

“真武门”   : (“师道殿”, ),

“拜火教”   : (“师道殿”, ),

“绝情谷”   : (“师道殿”, ),

“蛮王殿”   : (“师道殿”, ),

“药王宗”   : (“师道殿”, ),

“千魂塔二层”  : (“千魂塔一层”, ),

“平安镇”   : (“清水湾”, “逐风原”, ),

“帮派地图” : (“中州城”, ),

}

 

写一个函数FindPath(source, target),返回一个list,元素为从source到target所经过的各个地图名的一条即可。

# -*- coding: utf-8 -*-
DATA = {
   "中州城"  : ("师道殿", "云梦泽", "逐风原", "清水湾", "千魂塔一层", "帮派地图", ),
   "北漠城"  : ("鸣沙洲", "百花谷", ),
   "月牙湾"  : ("云梦泽", "伏波港", ),
   "伏波港"  : ("月牙湾", "百花谷", ),
   "鸣沙洲"  : ("北漠城", "苍茫山", ),
   "逐风原"  : ("平安镇", "中州城", ),
   "百花谷"  : ("北漠城", "伏波港", ),
   "千魂塔一层"    : ("千魂塔二层", "中州城", ),
   "云梦泽"  : ("月牙湾", "中州城", ),
   "苍茫山"  : ("鸣沙洲", ),
   "清水湾"  : ("中州城", "平安镇", ),
   "师道殿"  : ("绝情谷", "真武门", "蛮王殿", "中州城", "药王宗", "天策府", "拜火教", "清虚观", ),
   "清虚观"  : ("师道殿", ),
   "天策府"  : ("师道殿", ),
   "真武门"  : ("师道殿", ),
   "拜火教"  : ("师道殿", ),
   "绝情谷"  : ("师道殿", ),
   "蛮王殿"  : ("师道殿", ),
   "药王宗"  : ("师道殿", ),
   "千魂塔二层"    : ("千魂塔一层", ),
   "平安镇"  : ("清水湾", "逐风原", ),
   "帮派地图" : ("中州城", ),
}
 
lst = []
def FindPath(source ,target):
    if(source == target):
        return lst
    elif(target in lst):
        flag = True
        return lst
    for i in DATA[source]:
        if(i in lst):
            break
        else:
            lst.append(i)
            if(target in FindPath(i,target)):
                return lst
 
    return lst
 
list = FindPath("平安镇","中州城")
print(list)

 

(34) 有如下字符串

s = “””师门任务20次,0,80

除魔任务20次,0,100

闹事妖怪10次,0,50

运镖任务5次,0,40

挖宝5次,0,40

角色升级1次,0,50

完成4次江湖悬赏令,10,40

任务链整百环3次,0,90

获得修炼经验400点,0,50

野外暗雷战斗60次,0,50″””

将如上字符串解析为如下格式,注意对齐方式,以及第一项“今天总计”并不出现在s中,而是各行数字计算值。

# -*- coding: utf-8 -*-
import  re
s = """
   师门任务20次,0,80
   除魔任务20次,0,100
   闹事妖怪10次,0,50
   运镖任务5次,0,40
   挖宝5次,0,40
   角色升级1次,0,50
   完成4次江湖悬赏令,10,40
   任务链整百环3次,0,90
   获得修炼经验400点,0,50
   野外暗雷战斗60次,0,50"""
lst =  (re.findall(r"\d+",s))
 
#计算总数
count = 0
sum1 = 0
lst1 = []
sum2 = 0
lst2 = []
for i in lst:
    if (count % 3 == 1):
        sum1 = sum1 + int(i)
        lst1.append(i)
    elif (count % 3 == 2):
        sum2 = sum2 + int(i)
        lst2.append(i)
    count = count + 1
lst1.insert(0,str(sum1))
lst2.insert(0,str(sum2))
 
s1 = list(s)
count = 0
for i in range(0,len(s1)):
    if(s1[i] is ","):
        if(count % 2 == 0):
            s1[i] = ":"
            count = count + 1
        else:
            s1[i] = "/"
            count = count + 1
s = ''.join(s1)
s1 = re.split("\n\t|:",s)
 
count = 0
res = []
res.append("今天总计:")
for i in range(0,len(s1)):
    if(count % 2 == 0):
        count = count + 1
    else:
        res.append(s1[i])
        count = count + 1
 
 
print(" 每天完成以下事项可得活跃度")
tplt = "{0:{1}>10}"
for i in range(0,len(res)):
    print(tplt.format(res[i],chr(12288)),end="")
    print(":",end="")
    print(lst1[i],end="")
    print("/",end="")
    print(lst2[i])

 

(35)举例说明python中可变类型与不可变类型都有哪些?

不可变类型:数字、字符串、元组

可变类型:列表、字典

 

(36)编写函数,检测给定的两维列表中是否有重复数据(已知该列表中保存的是正整数):check_data(lList),如果没有重复,则函数返回真。要求算法的时间复杂度不大于O(n)。

# -*- coding: utf-8 -*-
lst1 = [['apple','banana','orange'],
        ['rabbit','tiger','forg'],
        ['microsoft','apple','amazon'],
        ['intel','amd']]
 
def check_data(List):
    map = {}
    for i in List:
        for j in i:
            if(j not in map):
                map[j] = 1
            else:
                return False
    return True
 
print(check_data(lst1))

 

Linux一切皆文件

和 Windows 系统不同,Linux 系统没有 C 盘、D 盘、E 盘那么多的盘符,只有一个根目录(/),所有的文件(资源)都存储在以根目录(/)为树根的树形目录结构中。
这样做最明显的好处是,开发者仅需要使用一套 API 和开发工具即可调取 Linux 系统中绝大部分的资源。举个简单的例子,Linux 中几乎所有读(读文件,读系统状态,读 socket,读 PIPE)的操作都可以用 read 函数来进行;几乎所有更改(更改文件,更改系统参数,写 socket,写 PIPE)的操作都可以用 write 函数来进行。

不利之处在于,使用任何硬件设备都必须与根目录下某一目录执行挂载操作,否则无法使用。我们知道,本身 Linux 具有一个以根目录为树根的文件目录结构,每个设备也同样如此,它们是相互独立的。如果我们想通过 Linux 上的根目录找到设备文件的目录结构,就必须将这两个文件系统目录合二为一,这就是挂载的真正含义。

 

远程服务器关机及重启时的注意事项

为什么远程服务器不能关机?原因很简单,远程服务器没有放置在本地,关机后谁帮你按开机电源键启动服务器?虽然计算机技术曰新月异,但是像插入电源和开机这样的工作还是需要手工进行的。如果服务器在远程,一旦关机,就只能求助托管机房的管理人员帮你开机了。

远程服务器重启时需要注意两点。

1) 远程服务器在重启前,要中止正在执行的服务

计算机的硬盘最怕在高速存储时断电或重启,非常容易造成硬盘损坏。所以,在重启前先中止你的服务,甚至可以考虑暂时断开对外提供服务的网络。

可能你会觉得服务器有这么娇贵吗?我的笔记本电脑经常强行关机,也没有发现硬盘损坏啊?这是因为你的个人计算机没有很多人访问,强制断电时硬盘并没有进行数据交换。小心驶得万年船!

2) 重启命令的选用

Linux 可以识别的重启命令有很多条,但是建议大家使用 “shutdown-r now” 命令重启。这条命令在重启时会正常保存和中止服务器中正在运行的程序,是安全命令。

最好在重启前执行几次 “sync” 命令,这条命令是数据同步命令,可以让暂时保存在内存中的数据同步到硬盘上。

重启和关机也是服务器需要注意的操作规范,不正确的重启和关机造成服务器故障的不在少数。

 

常见命令

cd 命令,是 Change Directory (改变目录)的缩写,用来切换工作目录。

pwd 命令,是 Print Working Directory (打印工作目录)的缩写,功能是显示用户当前所处的工作目录。

ls 命令,list 的缩写,是最常见的目录操作命令,其主要功能是显示当前目录下的内容。

mkdir 命令,是 make directories 的缩写,用于创建新目录,此命令所有用户都可以使用。

和 mkdir 命令(创建空目录)恰好相反,rmdir(remove empty directories 的缩写)命令用于删除空目录。

既然知道了如何在 Linux 系统中创建目录,接下来你可能会想在这些目录中创建一些文件,可以使用 touch 命令。需要注意的是,touch 命令不光可以用来创建文件(当指定操作文件不存在时,该命令会在当前位置建立一个空文件),此命令更重要的功能是修改文件的时间参数(但当文件存在时,会修改此文件的时间参数)。

cp 命令,主要用来复制文件和目录,同时借助某些选项,还可以实现复制整个目录,以及比对两文件的新旧而予以升级等功能。

rm 是强大的删除命令,它可以永久性地删除文件系统中指定的文件或目录。在使用 rm 命令删除文件或目录时,系统不会产生任何提示信息。

mv 命令(move 的缩写),既可以在不同的目录之间移动文件或目录,也可以对文件和目录进行重命名。

cat 命令可以用来显示文本文件的内容(类似于 DOS 下的 type 命令),也可以把几个文件内容附加到另一个文件中,即连接合并文件。

more 命令可以分页显示文本文件的内容,使用者可以逐页阅读文件中内容。

less 命令的作用和 more 十分类似,都用来浏览文本文件中的内容,不同之处在于,使用 more 命令浏览文件内容时,只能不断向后翻看,而使用 less 命令浏览,既可以向后翻看,也可以向前翻看。

 

Linux 系统中,每个文件主要拥有 3 个时间参数(通过 stat 命令进行查看),分别是文件的访问时间、数据修改时间以及状态修改时间:

  • 访问时间(Access Time,简称 atime):只要文件的内容被读取,访问时间就会更新。例如,使用 cat 命令可以查看文件的内容,此时文件的访问时间就会发生改变。
  • 数据修改时间(Modify Time,简称 mtime):当文件的内容数据发生改变,此文件的数据修改时间就会跟着相应改变。
  • 状态修改时间(Change Time,简称 ctime):当文件的状态发生变化,就会相应改变这个时间。比如说,如果文件的权限或者属性发生改变,此时间就会相应改变。