[Interviewfrage] Bitmap

Bitmap

Gegeben sind 4 Milliarden eindeutige Ganzzahlen ohne Vorzeichen, nicht sortiert. Wie kann man bei einer gegebenen ganzen Zahl ohne Vorzeichen schnell feststellen, ob eine Zahl zu den 4 Milliarden Zahlen gehört?

Mitte. 【Tencent】

  1. Durchquerung, Zeitkomplexität O(N)
  2. Sortieren (O(NlogN)) mit binärer Suche: logN

Beantragen Sie 512 MB Speicher

Ein Bit repräsentiert einen vorzeichenlosen int-Wert

Lesen Sie 4 Milliarden Zahlen ein und setzen Sie die entsprechenden Bits

Lesen Sie die abzufragende Zahl ein und prüfen Sie, ob das entsprechende Bit 1 ist. Wenn es 1 ist, bedeutet dies, dass es existiert, und wenn es 0 ist, bedeutet es, dass es nicht existiert.

Wir können jedes Binärbit verwenden, um ein Datenelement aufzuzeichnen. Ein int könnte nur ein Datenelement aufzeichnen, aber jetzt kann es 64 Zahlen aufzeichnen, was den Speicherplatz erheblich reduziert.

Auf einer Maschine mit Little-Endian-Speicher erfolgt die Speicherung folgendermaßen: Das High-Byte der Daten wird an der hohen Adresse des Speichers gespeichert, und das Low-Byte der Daten wird an der Low-Adresse gespeichert.

Ich möchte zum Beispiel 19 aufnehmen

19/8=2

19%8=3

Von 0 an gezählt, ursprünglich 19/8 = 2, also an der dritten Position des dritten Bytes ( die Position wird von 0 an gezählt ).

So fügen Sie Daten hinzu

Wenn ich die Daten 6 zur Bitmap hinzufügen möchte , ist der Status der initialisierten Bitmap vollständig 0.

Wie in der folgenden Abbildung gezeigt (der Anfangszustand der Bitmap):

0 0 0 0 0 0 0 0

6/8=0;

6%8=6;

Es handelt sich also um die 6. Stelle im 0. Byte.

Eine binäre Folge wie folgt kann konstruiert werden

0 1 0 0 0 0 0 0

Bitweises ODER (|) der beiden Binärsequenzen 0|1=1, 0|0=0, wodurch die Daten an anderen Positionen nicht geändert werden.

Wie baut man es also auf?

Verschieben Sie einfach 1 nach links (<<) j Positionen 1<<j.

So löschen Sie Daten

Wenn ich die Daten 6 aus der Bitmap löschen möchte

6/8=0;

6%8=6;

Es handelt sich also um die 6. Stelle im 0. Byte.

Wie in der folgenden Abbildung gezeigt (der Anfangszustand der Bitmap):

0 1 0 0 0 0 0 0

Eine binäre Folge wie folgt kann konstruiert werden

1 0 1 1 1 1 1 1

Bitweises UND (&) ** Die beiden Binärsequenzen 0&1=0, 0&0=0, 1&1=1 ändern die Daten an anderen Positionen nicht.

Wie baut man es also auf?

Verschieben Sie einfach 1 um j Positionen nach links (<<) und invertieren Sie es dann bitweise ~(1<<j).

Code

namespace mudan
{
    
    
	template<size_t N>
	class bitset
	{
    
    
	public:

		bitset()
		{
    
    
			_bits.resize(N / 8 + 1, 0);//计算出需要多少字节来存储
		}

		void set(size_t x)
		{
    
    
			size_t i = x / 8;
			size_t j = x % 8;

			_bits[i] |= (1 << j);
		}

		void reset(size_t x)
		{
    
    
			size_t i = x / 8;
			size_t j = x % 8;

			_bits[i] &= ~ (1 << j);
		}

		bool test(size_t x)
		{
    
    
			size_t i = x / 8;
			size_t j = x % 8;

			return _bits[i] & (1 << j);
		}

	private:
		vector<char> _bits;
	};

	void test_bit_set1()
	{
    
    
		bitset<100> bs1;
		bs1.set(8);
		bs1.set(9);
		bs1.set(20);

		cout << bs1.test(8) << endl;
		cout << bs1.test(9) << endl;
		cout << bs1.test(20) << endl;

		cout <<"=====================" << endl;
		bs1.reset(8);
		bs1.reset(9);
		bs1.reset(20);

		cout << bs1.test(8) << endl;
		cout << bs1.test(9) << endl;
		cout << bs1.test(20) << endl;
	}
}

Die Testergebnisse zeigen, dass es normal läuft und Sie diese Nummer finden können. Nach dem Löschen können Sie sie nicht mehr finden.

Wie finde ich bei 10 Milliarden ganzen Zahlen eine Zahl, die nur einmal vorkommt?

Zur Erfassung der Situation können zwei Bitmaps verwendet werden

Einstufung:

Erscheint 0 Mal: ​​00

Erscheint 1 Mal: ​​01

Mehr als 1 Mal: ​​10

Code

template<size_t N>
	class twobitset
	{
    
    
	public:

		void set(size_t x)
		{
    
    
			bool inset1 = _bs1.test(x);
			bool inset2 = _bs2.test(x);
			
			//00的情况
			if (inset1 == false && inset2 == false)
			{
    
    
				//变成01,出现一次
				_bs2.set(x);
			}
			else if (inset1 == false && inset2 == true)
			{
    
    
				//出现了一次,变成一次以上
				_bs1.set(x);//1
				_bs2.reset(x);//0
			}
			else if (inset1 == true && inset2 == false)
			{
    
    
				//10->11
				_bs1.set(x);
				_bs2.set(x);
			}
		}

		void print_once_num()
		{
    
    
			for (size_t i = 0; i < N; ++i)
			{
    
    
				if (_bs1.test(i) == false && _bs2.test(i) == true)
				{
    
    
					cout << i << endl;
				}
			}
		}

	private:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};

	void test_bit_set3()
	{
    
    
		int a[] = {
    
     3, 4, 5, 2, 3, 4, 4, 4, 4, 12, 77, 65, 44, 4, 44, 99, 33, 33, 33, 6, 5, 34, 12 };

		twobitset<100> bs;
		for (auto e : a)
		{
    
    
			bs.set(e);
		}

		bs.print_once_num();
	}

Wie Sie sehen, werden die Zahlen herausgefiltert, die nur einmal vorkommen.

Analog kann diese Methode zwei-, drei-, vier-, fünf- und sechsmal angewendet werden.

Wie finde ich bei zwei Dateien mit jeweils 10 Milliarden Ganzzahlen, aber nur 1 g Speicher den Schnittpunkt der Dateien?

Das ist eigentlich einfach: Öffnen Sie zwei Bitmaps und durchlaufen Sie die Bitmaps. Wenn 1 1 bedeutet, dass es einen Schnittpunkt gibt, andernfalls gibt es keinen Schnittpunkt.

1 Datei hat 10 Milliarden Ints und 1 GB Speicher. Entwerfen Sie einen Algorithmus, um alle Ganzzahlen zu finden, die nicht mehr als zweimal vorkommen.

Erfassen Sie ähnlich wie bei der vorherigen Lösung mehrere Zustände

0 Mal: ​​00

1 Mal: ​​01

2 Mal: ​​10

3 Mal und mehr: 11

Supongo que te gusta

Origin blog.csdn.net/AkieMo/article/details/132073590
Recomendado
Clasificación