劍指offer中的程式碼題2.1-2.2
阿新 • • 發佈:2018-12-22
Q49:字串轉數字
一般解:
int StrToInt(char* string)
{
int number=0;
while(*string !=null)
{
number=10*number+*string-‘0’;
++string;
}
return number;
}
//還要考慮:輸入為空?字串中有非數字?正負數?返回值是int,int的大小限制返回數字的大小,所以輸入的字元是否會造成溢位?
進階解:
Q:求連結串列倒數第K個節點
思路:兩個指標,相差K個節點,一起走,最後一個走到底,另一個就是倒數第K個節點
一般解:
ListNode * FindKthToTail(ListNode * pListHead, unsigned int k) { if(pListHead==NULL) return NULL; ListNode *pAhead = pListHead; ListNode *pBehind =NULL; for(unsigned int i=0;i<k-1;++i)//與while的判斷條件協調 pAhead=pAhead -> m_pNext; pBehind = pListHead; while(pAhead -> m_pNext!=NULL) { pAhead=pAhead -> m_pNext; pBehind=pBehind -> m_pNext; } return pBehind; } //還要考慮:節點數<k怎麼辦?k為0?
Q:為類CMyString定義一個賦值運算子的函式
注:考慮連續賦值的情況,返回型別應為該型別的引用,並在函式結束前返回例項自身的引用(*this);考慮效率,且複製過程不改變傳入的例項的狀態,所以引數型別為常量引用;考慮記憶體洩漏,是否釋放自身已有記憶體,考慮傳入的引數和當前例項相同,應直接返回,否則釋放自身記憶體的時候會出現找不到需要賦值的內容的操作。
class CMyString { public: CMyString(char * pData =NULL); CMyString(const CMyString & str); ~CMyString(void); private: char * m_pData; }; //初級解 CMyString & CMyString::operator=(const CMyString & str) { if(this == & str) return *this; delete []m_pData; m_pData=NULL; m_pData= new char[strlen(str.m_pdata)+1]' strcpy(m_pData,str.m_pData); return *this; } //上述方法中,先delete再new,如果記憶體不足導致new的過程中丟擲異常,m_pData將會是一個空指標。 //可以先分配,成功再釋放原始內容,也可以先建立臨時例項,再交換臨時例項和原來的例項 CMyString & CMyString::operator=(const CMyString & str) { if(this !=&str) { CMyString strTemp(str); char* pTemp =strTemp.m_pData; strTemp.m_pData=m_pData; m_pData=pTemp; } return *this; }
Q:設計一個類,只能生成該類的一個例項
解:Singleton
/*初級解
只能生成一個例項,必須把建構函式設定為私有,防止他人建立例項。可以定義一個靜態的例項,在需要的時候建立該例項*/
public sealed class Singleton1
{
private Singeleton1()//私有
{
}
private static Singleton1 instance =null;//當為null才建立
public static Singleton1 Instance
{
get
{
if(instance ==null)
instance =new Singleton1;
return instance ;
}
}
}
/*如果是多執行緒的情況,兩個執行緒同時執行到判斷instance是否為null,如果此時instance沒有建立,那麼連個執行緒都會建立例項,這不滿足單例模式的要求。加鎖*/
public sealed class Singleton2
{
private Singleton2()
{}
private static readonly object syncObj = new object();
private static Singleton2 instance = null;
public static Singleton2 Instance
{
get
{
lock(syncObj)//加鎖耗時,追加判斷條件
{
if(instance == null)
instance =new Singleton2();
}
return instance;
}
}
}
//兩次判斷
public sealed class Singleton3
{
private Singleton3()
{}
private static readonly object syncObj = new object();
private static Singleton3 instance = null;
public static Singleton3 Instance
{
get
{
if(instance ==null)
{
lock(syncObj)//加鎖耗時,追加判斷條件
{
if(instance == null)
instance =new Singleton2();
}
}
return instance;
}
}
}
//程式碼太複雜了,利用c#的靜態建構函式,該函式的特性是確保只調用一次
public sealed class Singleton4
{
private Sinleton4(){}
private static Sinleton4 instance =new Singleton4;
public static Singleton4 Instance
{
get
{
return instance;
}
}
}
/*簡潔啊,在初始化靜態變數instance的時候建立了一個例項,c#在呼叫靜態建構函式是初始化靜態變數,.net在執行時能保證只調用一次靜態建構函式,這樣就能保證只初始化一次instance。c#中呼叫靜態建構函式的時機不是程式設計師控制的,當.NET執行時發現,第一次使用一個類的時候,會自動呼叫該類的今天建構函式,也就是說,例項instance並非在呼叫Singleton4.Instance的時候建立,而是在第一次使用到Singleton4的時候就會被建立。如果我們在Singleton4中新增一個靜態方法,該函式不需要建立一個例項,可是按照上述方式實現,會過早建立例項,降低記憶體使用效率*/
public sealed class Singleton5
{
private Sinleton5(){}
public static Singleton5 Instance
{
get
{
return Nest.instance;
}
}
class Nested //巢狀型別
{
static Nested()//私有屬性
{
}
internal static readonlu Singleton5 instance =new Singkleton5();
}
}