学习编程艺术的心得、知识总结1(长期更新)


本文章用于记录阅读七月大神的博客编程艺术的心得、知识,在看了两三章节的过程中,每次都是先看思路,自己编写调试后和他的代码对比,在自己编写过程中,发现了自己对编程知识方法的许多错误使用,同时学习到了简洁的编程方式。在整个阅读过程,想到遇到什么都记录一下,在反思中学习进步!!

七月的编程艺术github版网址:https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/Readme.md。


一、字符串包含

知识点:

1、对string类型的变量a使用sort排序:
sort(a.begin(),a.end());
2、算法的位运算实现,比较经典,对位操作比较陌生,代码记录在此,方便随时学习。
// “最好的方法”,时间复杂度O(n + m),空间复杂度O(1)
bool StringContain(string &a,string &b)
{
    int hash = 0;
    for (int i = 0; i < a.length(); ++i)
    {
        hash |= (1 << (a[i] - 'A'));
    }
    for (int i = 0; i < b.length(); ++i)
    {
        if ((hash & (1 << (b[i] - 'A'))) == 0)
        {
            return false;
        }
    }
    return true;
}

二、字符串转换为整数

按照最初的想法,直接读取字符串中的一个,然后转为数字,然后以num=num*10+m更新即可,自己写了如下的函数来实现。

int StrToInt1(const char *str)
{
	int num=0;
	while(str)
	{
		int m=*str-'0';
		num=num*10+m;
		str++;
	}
	return num;
}

结果发现运行出错。原因是,str指针已经被赋值了,在str++的过程中,str始终不为一个空指针,while循环的判断条件一直成立,因此出错。此时,参考博客,将while判断改为*str==0即可,即指针指向的值为0。

知识点:

设置int型数的最大值和最小值,用位运算实现如下:

    static const int MAX_INT = (int)((unsigned)~0 >> 1);
    static const int MIN_INT = -(int)((unsigned)~0 >> 1) - 1;

三、回文判断

当实现函数的参数形式如下为string类型时:

bool palind(string *s, int n)
此时直接看成数组,设定i从0到s.length()/2即可。

当实现函数的参数形式如下时:

bool palind(const char *s, int n)

字符串用字符指针s来表示的,此时用两个指针指示首尾,依次改变指针指向进行比较。此时对两个指示指针赋值如下:

char *first,*last;
	first=s;
	last=s+n-1;
结果出现了如下错误:

error C2440: '=' : cannot convert from 'const char *' to 'char *'
在网上查找解决办法是进行强制转化,修改如下:

char *first=(char *)s;
char* last=(char *)(s+n-1);

四、字符串全排列

输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符a、b、c 所能排列出来的所有字符串abc、acb、bac、bca、cab 和 cba。

在看到题目后,想到以前做过的一个深度优先遍历题目,此题也可使用此思路,从a开始查找到b再到底部c返回一条路径,然后向上返回,查找到c再到b。然后返回到最开始,从b开始查找。

下面是基于此深度搜索的实现代码:

#include<iostream>
#include<string>
using namespace std;

string a="abcd";
int lu[4];  //保存路径
int rest[4];//剩余未访问的字符
int j=0,restone_temp=-1; //j为路径计数,restone_temp为剩余一个未访问时,此未访问节点的下标,
<span style="white-space:pre">		</span>//因为剩余一个未访问时,路径已经确定,此设置方便返回到上一步选择的节点
bool restone()  //判断是否剩余一个未访问
{
	int count=0;
	int k=-1;
	for(int i=0;i<a.length();i++)
	{
		if(rest[i]==1)
		{
			count++;
			k=i;
		}
			
	}
	if(count==1)
	{
		restone_temp=k;  //记录还有一个未访问时,此节点的下标
		return true;
	}		
	else
		return false;
}
void strsort()
{
	if(restone())   //剩余一个即确定了组合方式,打印结果
	{
		for(int i=0;i<a.length()-1;i++)
			cout<<a[lu[i]];
		cout<<a[restone_temp];
		cout<<endl;
		return;
	}
	
	for(int i=0;i<a.length();i++)
	{
		if(rest[i])
		{
			rest[i]=0;
			lu[j++]=i;
			strsort();  //递归

			rest[i]=1;  //返回上一步选择的节点,如果访问到最后一个才返回,需要向上返回两次,
			j--;<span style="white-space:pre">	</span>//但返回两次时,向上返回的节点难以确定
		}		
	}
}

int main()
{
	for(int i=0;i<a.length();i++)
		rest[i]=1;
	strsort();
	return 0;
}
(⊙﹏⊙)汗。。检查了一下代码,发现上述的代码判断剩余一个未访问的操作完全多余,在递归过程中,在向上返回一次时,因为没有其他路径可走,又会自动向上返回一次,因此上述代码严重冗余。 对深度搜索的递归实现认识还不足,需要进一步学习。 改进的代码如下:

#include<iostream>
#include<string>
using namespace std;

string a="abcd";
int lu[4];
int rest[4];
int j=0;

bool norest()  //判断是否所有点已经被访问
{
	for(int i=0;i<a.length();i++)
	{
		if(rest[i]==1)
			return false;			
	}
	return true;
}

void strsort()
{
	if(norest())  //所有点被访问,打印路径
	{
		for(int i=0;i<a.length();i++)
			cout<<a[lu[i]];
		cout<<endl;
		return;
	}
	for(int i=0;i<a.length();i++)
	{
		if(rest[i])
		{
			rest[i]=0;
			lu[j++]=i;
			strsort();

			rest[i]=1;
			j--;
		}		
	}
}

int main()
{
	for(int i=0;i<a.length();i++)
		rest[i]=1;
	strsort();

	return 0;
}

而作者文中的递归实现,使用了交换操作,勉强理解了,感觉实现有点复杂。

第二种方法是基于字典序排列,即使用了STL中的next_permutation算法思想来实现的,再往后的实现中,可直接循环调用此函数来实现全排列,可大大简化代码,下面用此函数实现字符串的全排列如下:

#include<iostream>
#include<string>
#include <algorithm>
using namespace std;

int main()
{
	char ch[200];
	cin>>ch;
	sort(ch,ch+strlen(ch));
	do{
		cout<<ch<<endl;
	}while(next_permutation(ch, ch+strlen(ch)));

	return 0;
}
思考题中,已知字符串里的字符是互不相同的,现在任意组合,比如ab,则输出aa,ab,ba,bb,作者提供的解决方法非常巧妙,也是基于递归实现的,记录在此:

#include<iostream>
#include<string>
#include <algorithm>
using namespace std;

void perm(char* result, char *str, int size, int resPos)
{
  if(resPos == size)
    printf("%s\n", result);
  else
    {
      for(int i = 0; i < size; ++i)
        {
          result[resPos] = str[i];
          perm(result, str, size, resPos + 1);
        }
    }
}

int main()
{
	char ch[200];
	cin>>ch;
	sort(ch,ch+strlen(ch));
	char result[200]={0};
	perm(result,ch,strlen(ch),0);

	return 0;
}

五、最小的K个数

其中使用堆来维护K个数的集合还没实现,因为一直以来对堆就很陌生,所以没实现。下面是直接根据快速选择思路实现的代码:

#include<iostream> 
#include<algorithm>
using namespace std;  

int median3(int a[],int first,int last)
{
	int midium=(first+last)/2;
	if(a[first]>a[midium]&&a[first]>a[last])
	{
		if(a[midium]>a[last])
			return midium;
		else 
			return last;
	}
	if(a[first]<a[midium]&&a[first]<a[last])
	{
		if(a[midium]<a[last])
			return midium;
		else 
			return last;
	}
	return first;
}

void quickselect(int s[],int first,int last,int k)
{
	int m=0,n=0;
	int piv=0;
	int s1[100],s2[100];
	
	piv=median3(s,first,last);
	for(int i=0;i<=last;i++)
	{
		if(s[i]>=s[piv])
		{
			s2[n++]=s[i];
		}
		else 
			s1[m++]=s[i];
	}
	if(k>m)
	{
		for(int j=first;j<n;j++)
			cout<<s1[j]<<" ";
		quickselect(s2,0,n-1,k-m);
	}		
	else if(k<m)
		quickselect(s1,0,m-1,k);
	else
	{
		for(int j=first;j<m;j++)
			cout<<s1[j]<<" ";
		cout<<endl;
	}
}

int main()
{
	int arr[100]={462359,161047,2346,716099,189159,264108,905891,115240,473403,221514,
				723403,684465,257361,34611,535903,478932,345173,117798,693203,593953};
	quickselect(arr,0,19,10);	
	return 0;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python中进行数据库编程,最常用的是使用Python的标准库中的sqlite3模块来进行SQLite数据库的操作。以下是我对Python中数据库编程的一些学习心得: 1. 连接数据库 使用sqlite3模块连接SQLite数据库,首先需要使用connect()方法创建一个连接对象,该方法需要传入数据库文件路径作为参数。例如: ``` import sqlite3 conn = sqlite3.connect('test.db') ``` 2. 创建表 创建表需要使用execute()方法执行SQL语句。例如: ``` import sqlite3 conn = sqlite3.connect('test.db') cursor = conn.cursor() sql = ''' CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, name TEXT, age INTEGER ) ''' cursor.execute(sql) conn.commit() conn.close() ``` 3. 插入数据 插入数据需要使用execute()方法执行INSERT语句。例如: ``` import sqlite3 conn = sqlite3.connect('test.db') cursor = conn.cursor() sql = "INSERT INTO users (name, age) VALUES (?, ?)" cursor.execute(sql, ('Alice', 20)) conn.commit() conn.close() ``` 4. 查询数据 查询数据需要使用execute()方法执行SELECT语句,并使用fetchone()或fetchall()方法获取结果。例如: ``` import sqlite3 conn = sqlite3.connect('test.db') cursor = conn.cursor() sql = "SELECT * FROM users WHERE age > ?" cursor.execute(sql, (18,)) result = cursor.fetchall() for row in result: print(row) conn.close() ``` 5. 更新数据 更新数据需要使用execute()方法执行UPDATE语句。例如: ``` import sqlite3 conn = sqlite3.connect('test.db') cursor = conn.cursor() sql = "UPDATE users SET age = ? WHERE name = ?" cursor.execute(sql, (21, 'Alice')) conn.commit() conn.close() ``` 6. 删除数据 删除数据需要使用execute()方法执行DELETE语句。例如: ``` import sqlite3 conn = sqlite3.connect('test.db') cursor = conn.cursor() sql = "DELETE FROM users WHERE name = ?" cursor.execute(sql, ('Alice',)) conn.commit() conn.close() ``` 以上是我对Python中数据库编程的一些学习心得,希望能对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值