剣はオファー質問21を指します-奇数の本が偶数の前に来るように配列の順序を調整します

奇数の本が偶数の前にくるように配列の順序を調整します

トピック

整数配列を入力し、すべてのカウントが配列の前半にあり、すべての偶数が配列の後半にあるように、配列内の数値の順序を調整する関数を実装します。

初期分析

もちろん、最も簡単な方法は、配列を最初からスキャンすることです。偶数に遭遇するたびに、番号は最後に配置されます。つまり、番号の後の番号を前に移動する必要があります。
O(n)の数は偶数に遭遇するたびに移動するため、合計時間計算量はO(n ^ 2)です。

より良い方法

配列には奇数または偶数の2種類の数値しかないためです。それで、奇数の前に偶数が表示されているのを見つけたら、それらの順序を入れ替えても大丈夫ですか?

したがって、2つのポインターを維持する必要があります
。初期化時に最初の番号を指す最初のポインターは、後方にのみ移動できます。
2番目のポインタは、初期化されたときに最後の番号を指し、前方にのみ移動できます。

2つのポインターが出会う前に、最初のポインターが偶数で2番目のポインターが奇数の場合は、それらの位置を入れ替えます。

例えば

入力配列:{1、2、3、4、5}

プロセス:
1。最初に、最初のポインターは1を指し、2番目のポインターは5 2を指します
。1は奇数であるため、最初のポインターは偶数2を指すまで後方に移動します。
3.このとき、2番目のポインターは5を指しているため、スワップして両方が移動します。
4.次に、2つが出会うまで続けます

イラスト:
ここに画像の説明を挿入
次のコードを取得できます:

void ReorderOddEven(int* pData,unsigned int length)
{
    
    
	if(pData==nullptr || length==0)
		return;
	int* pBegin=pData;
	int* pEnd=pData+length+1;
	
	while(pBegin<pEnd)
	{
    
    
		//向后移动pBegin 直到它指向偶数
		while(pBegin<pEnd && (*pBegin & 0x1)!=0)
			pBegin++;
		//向前移动pEnd 直到指向奇数
		while(pBegin<pEnd && (*pEnd & 0x1)==0)
			pEnd--;
		if(pBegin<pEnd)
		{
    
    
			int temp=*pBegin;
			*pBegin=*pEnd;
			*pEnd=tmp;
		}
	}
}

拡張モジュラー処理

上記の問題は解決され、完璧に見えますが、同様の問題がある場合はどうなりますか?

質問:配列が正と負の2つの部分に分割され、負の数が非負の数の前にある場合、どのように対処しますか?
A:新しい関数を再定義するには、の判断条件を変更するだけです。 2番目と3番目のwhileループ。

別の質問をします。2つの部分に分割すると、1つの部分は3で割り切れ、前の部分は3で割り切れず、後の部分は3で割り切れます。
もう一度答えてください:または、新しい関数を再定義して、もう一度変更してください...割り込み:停止して停止します。これ以上の方法はありませんか?

上記の質問を見ると、答えは間違っていないので、条件を変更するだけです。
しかし、上記は間違っています、これは上記だけです

変更が必要なのは単なる判断条件なので、毎回同じコードを繰り返す必要があるのはなぜですか?
残りのコードを再利用できないように、判断が必要な条件をカプセル化してみませんか?
そうです、正式な質問者が望んでいた答えです!

したがって、関数ポインターを導入し、上記のコードをロジックと操作の2つの部分に分割するだけで済みます。このように、多数の計算を繰り返すのではなく、毎回論理関数を書き直すだけで済み、再利用性が大幅に向上します。

void ReorderOddEven(int* pData,unsigned int length,bool (*func)(int))
{
    
    
	if(pData==nullptr || length==0)
		return;
	int* pBegin=pData;
	int* pEnd=pData+length+1;
	
	while(pBegin<pEnd)
	{
    
    
		//向后移动pBegin 直到它指向偶数
		while(pBegin<pEnd && !func(*pBegin))
			pBegin++;
		//向前移动pEnd 直到指向奇数
		while(pBegin<pEnd && func(*pEnd) )
			pEnd--;
		if(pBegin<pEnd)
		{
    
    
			int temp=*pBegin;
			*pBegin=*pEnd;
			*pEnd=tmp;
		}
	}
}

bool IsEven(int n)
{
    
    
	return (n&0x1)==0;
}

—————————————————————————————————————————————————— ————
参考書:「ソードフィンガーオファー」

おすすめ

転載: blog.csdn.net/rjszz1314/article/details/104286378