Vodič za pitanja za intervju za Python: kako kodirati povezani popis

Uvijek sam razumio temeljni koncept povezanih popisa, ali nikada ga nisam provodio u praksi.

Tek sam u svom prvom razgovoru s Amazonom prije nekoliko godina shvatio da nemam pojma kako se koncept Povezanih popisa pretočio u kod.

I zato pišem ovaj vodič!

Cilj mi je pomoći vam da se zaposlite kao softverski inženjer.

Želim pokriti puno pitanja o intervjuima na povezanim listama, a ovaj je članak prvi korak u tom procesu. Pa zaronimo.

Što je povezani popis?

Povezani popis je struktura podataka koja se sastoji od mnogih struktura mini podataka koji se nazivaju 'Čvorovi'. Čvorovi se povezuju kako bi stvorili popis.

Svaki čvor sadrži 2 atributa

  1. Njegova vrijednost. To može biti bilo što: cijeli brojevi, znakovi, nizovi, objekti itd.
  2. Pokazivač na sljedeći čvor u nizu.

Neke definicije

'Glavni čvor': Glavni čvor je jednostavno prvi čvor na povezanom popisu. Kao što vidimo iz gornjeg primjera, čvor koji sadrži '5' je prvi čvor, a time i glava.

' Repni čvor ': Zadnji čvor je posljednji čvor u nizu. Budući da je posljednji čvor, pokazuje na nulu, jer u slijedu ne postoji sljedeći čvor. U gornjem primjeru čvor koji sadrži '3' bio bi repni čvor.

Pojedinačno i dvostruko povezani

Kada je riječ o povezanim popisima, postoje dvije glavne vrste.

Oni koji su 'pojedinačno' povezani i oni koji su 'dvostruko' povezani.

Pojedinačno povezano znači da svaki čvor pokazuje samo na najviše 1 drugi čvor, čvor ispred njega. To je izloženo u gornjem primjeru.

Dvostruko povezano znači da svaki čvor može usmjeriti na 2 druga čvora, čvor ispred sebe i čvor iza sebe. Kao što možemo vidjeti iz primjera u nastavku, budući da ne postoji čvor koji prethodi glavnom čvoru (koji je 5), jedan od njegovih pokazivača pokazuje na nulu.

U redu, razumijem sve to. Ali kako funkcionira kod?

Kodiranje povezanih popisa može biti problem s 4 retka ili s 400 linija. Ovisi o tome kako mu želite pristupiti.

Na najjednostavnijoj razini, kao što smo razgovarali, povezani je popis samo hrpa povezanih čvorova.

Dakle, sve što nam je stvarno potrebno za stvaranje ove strukture je objekt čvora.

class linkedListNode: def __init__(self, value, nextNode=None): self.value = value self.nextNode = nextNode

Ovdje možemo vidjeti da smo jednostavno stvorili klasu koja ima atribut value i nextNode.

Da bismo stvorili čvor, jednostavno unesemo vrijednost.

node1 = linkedListNode("3") # "3"node2 = linkedListNode("7") # "7"node3 = linkedListNode("10") # "10"

Ovdje smo stvorili 3 pojedinačna čvora.

Sljedeći je korak jednostavno njihovo povezivanje.

node1.nextNode = node2 node2.nextNode = node3 

Prvi redak gore čini čvor1 usmjeren na čvor2:

“3” → “7”

Drugi redak gore čini node2 usmjerenim na node3:

“7” → ”10"

Sve skupa, ostaje nam povezani popis koji izgleda ovako:

“3” → ”7” → ”10” → Null

Napomena: “10” pokazuje na nulu, jer node3 nije dodijeljen nextNode, a zadani nextNode je Null.

Kao što sam već spomenuo, postoji puno različitih načina za to. Ovo je samo najjednostavnije.

Ako pokušavate izraditi cijelu klasu LinkedList, ovaj video detaljno opisuje kako to učiniti.

Obilazak povezanog popisa

Ako radite programski intervju i ako vam se postavi pitanje povezanog popisa, nećete dobiti sve čvorove.

Dobit ćete samo glavni čvor.

Iz tog glavnog čvora morate dobiti ostatak popisa.

Prvo shvatimo kako dobiti vrijednost i nextNode iz čvora u Pythonu.

Recimo da imamo čvor jednostavno nazvan 'čvor'.

Dobivanje vrijednosti čvora:

node.value

Dobivanje nextNode čvora:

node.nextNode

Preokret

Prvo što želimo učiniti je stvoriti varijablu koja se naziva "currentNode" koja prati čvor u kojem se nalazimo. Prvo to želimo dodijeliti našem glavnom čvoru.

currentNode = head

Sada sve što moramo učiniti je jednostavno provjeriti je li naš trenutni čvor Null ili nije. Ako nije, učinit ćemo naš 'currentNode' jednakim 'nextNode' 'currentNode'.

currentNode = node1while currentNode is not None: currentNode = currentNode.nextNode

Recimo da imamo sljedeći povezani popis: “3” → ”7” → ”10”.

Naša glava i prvi 'currentNode' je "3".

Kad to učinimo

currentNode = currentNode.nextNode

Dodjeljujemo 'currentNode' susjedu našeg trenutnog čvora, što je u ovom slučaju "7".

To se nastavlja sve dok trenutni Čvor ne bude usmjeren na Ništa, u tom slučaju se petlja zaustavlja.

And that is the basic way to traverse through a Linked List in Python.

Link to the code on Github.

Inserting elements

When you insert an element into a linked list, you insert it into the back unless specified otherwise.

Let’s use the following example:

“3”→”7"→”10"→Null

Let’s say we want to insert a “4”.

We would simply find the tail node, in this case “10”, and set its nextNode to our “4” node.

“3”→”7"→”10"→“4”→Null

node4 = linkedListNode("4")node3.nextNode = node4

Now let’s say we were in an interview, and all we had was the head node.

We simply traverse through the LinkedList to find the tail. Once we have the tail, we simply set its nextNode to our new node that we create.

def insertNode(head, valuetoInsert): currentNode = head while currentNode is not None: if currentNode.nextNode is None: currentNode.nextNode = linkedListNode(valuetoInsert) return head currentNode = currentNode.nextNode

Deleting elements

Deleting can get a bit tricky.

Let’s take the same example.

“3”→”7"→”10"→Null

If we wanted to delete the “7”, all we need to do is point the “3” to the “10” so that the “7” is never referenced.

“3”→”10"→Null

To do this, we would have to traverse the list while not only keeping track of the currentNode, but also keeping track of the previousNode.

We would also have to account for the head node being the node we want to delete.

In the code below, we simply delete the first instance of the value we want to delete.

Note that there are many ways to accomplish this, and the solution below might not be the cleanest code you’ll see in your life. However, in the heat of an interview, the interviewer probably won’t expect textbook perfect code.

def deleteNode(head, valueToDelete): currentNode = head previousNode = None while currentNode is not None: if currentNode.value == valueToDelete: if previousNode is None: newHead = currentNode.nextNode currentNode.nextNode = None return newHead # Deleted the head previousNode.nextNode = currentNode.nextNode return head previousNode = currentNode currentNode = currentNode.nextNode return head # Value to delete was not found.

In the code above, once we find the node we want to delete, we set the previous node’s “nextNode” to the deleted node’s “nextNode” to completely cut it out of the list.

Big O Time Complexity Analysis

**NOTE** These are the time complexities for the node structure above, which is most likely to appear on an interview. In practical cases, you can store attributes in a LinkedList class to lower these complexities.

‘n’ = the amount of elements inside the Linked List.

Inserting to the back of the Linked List— We go through all n elements to find the tail and insert our new node. O(n)

Inserting to the front of the Linked List — We simply create the new node and set its nextNode to the head. No need to traverse the list. O(1)

Traversing — We go through all n elements once. O(n)

Deleting — Worst case scenario, the node we’re deleting is the last node, causing us to traverse through the entire list. O(n)

You can now tackle Linked List interview questions!

You now have the fundamental knowledge you need to start tackling Linked List interview questions!

They can start off easy, and get tough really quick.

In the next article, I’m going to go over a couple of common questions and techniques you can use to solve them.

If you’re a student looking to land your dream internship or full-time job within the next 2 years, start practicing now!

I’ve started a community (www.theforge.ca) where we connect students with mentors and industry experts that help them navigate their way to their dream job.

Thanks for reading, and good luck!