Algoritmusok

Mindig kell a lépésszám is!

1.

Írjon le két algoritmust a legnagyobb elem megtalálására!

def max_1(A):
	max_index = 0
	for i in range(1, n):
		if A[i] > A[max_index]:
			max_index = i
	return max_index

def max_2(A): # dumb way to write recursion, but this is in the book...
	n = len(A)
	if n = 0:
		return 0
			
	j = max_2(A[:-1])
	if A[j] > A[-1]:
		return j
	else:
		return n-1
 
def max_2(A): # better, tail recursive, more elegant way of writing recursion
	def helper(A, maximal):
		if len(A) == 1:
			return A[0]
		hd, tl = A[0], A[1:]
		return helper(tl, max(hd, maximal))
	return helper(A, A[0])
let max_list list =
	let rec aux list maximal =
		match list with
		| [] -> 0
		| hd :: tl -> aux tl (max hd maximal)
	in
	aux list (List.hd list)

2.

Írja le az összefésülő rendezés algoritmusát!

def mergesort(A):
	if len(A) == 1:
		return A
	mid = len(A) // 2
	B = mergesort(A[:mid])
	C = mergesort(A[mid:])
	return merge(B, C)
 
def merge(B, C):
	result = []
	p, q = len(B), len(C)
	i, j = 1, 1
	while i < p and j < q:
		if B[i] <= C[j]:
			result[i + j + 1] = B[i]
			i += 1
		else:
			result[i + j + 1] = C[j]
			j += 1
	if i > p:
		for k in range(j, q):
			result[q + k] = B[k]
	else:
		for k in range(i, p):
			result[q + k] = C[k]
 
	return result

3.

Hogyan megy kupacokban a MINTÖRLÉS?

class Heap:
	def __init__(self, lst=None):
		if lst is None:
			self.lst = []
		else:
			self.lst = lst
		self.end = -1
 
	def min_pop(self):
		swap(self.lst[0], self.lst[self.end])
		self.end -= 1
		self.sink_down(i = 0)
		return self.lst[self.end + 1]
 
	def sink_down(self, i):
		num = self.lst[i]
		j = 2*i + 1
		while j < self.end + 1:
			if self.lst[j - 1] < self.lst[j]:
				j -= 1
			if self.lst[j] < num: # num is greater than the smaller child
				self.lst[i] = self.lst[j]
				i = j
				j = 2*i + 1
			else:
				break # we are done
		j -= 1
		if j < self.end + 1 and self.lst[j] < num:
			self.lst[i] = self.lst[j]
			i = j
		self.lst[i] = num
 

Beszúrás:
Becseréljük az első elemet az utolsóval.
Megjegyezzük az utolsó elemet és utána töröljük
Lebillegtettjük az első elemet.
Vissza adjuk a megjegyzett elemet

Lebillegtetés:
Megnézzük, hogy a két gyerek közül melyik a kisebb és azzal összehasonlítjuk a szülőt.
Ha a szülő kisebb, mint a kisebbik gyerek akkor mindkettőnél kisebb és készen vagyunk
Ha a szűlő nagyobb, mint a kisebbik gyerek akkor a kisebbik gyereket felemeljük a szülő helyére és a szülőt levisszük a gyerek helyére.
Tovább folytatujuk a levitt szülővel az iterálást, míg le nem állunk

4.

Hogyan megy a gyors kupacépítés és a kupacos rendezés?

kupacrendezés:
kupacépítés:

def heap_sort(lst):
	h = Heap()
	base_list = []
	for x in lst:
		base_list.append(x)
	h = Heap(base_list)
	for i in range(len(h.lst) // 2, 0, -1):
		h.sink_down(i)
	result = []
	while h.end > -1:
		result.append(h.min_pop())
	return result

5.

Írja le a leszámláló és a számjegyes rendezés algoritmusait!

def lesz_rend(A, m):
	aux = [0 for _ in range(m + 1)]
	for j in range(n):
		aux[A[j]] += 1
 
	for i in range(1, m + 1):
		aux[i] += aux[i - 1]
		   
	res = [-1 for _ in range(n)]
	for j in range(n, 0, -1):
		res[aux[A[j]]] = j
		aux[A[j]] -= 1
	return res

Számjegyes rendezés: Adot természetes számok, ahol minden -re valamilyen alapú számredszerben.

A számjegyes rendezés annyit csinál, hogy az inputot leszáláló rendezéssel rendezi először a legszignifikánsabb számjegy alapján aztán a következő alapján stb.

6.

Írja le Euklidesz algoritmusát!

bitműveletekben

def gcd(a, b):
	if a == 0:
		return b
	return gcd(b % a, a)
let gcd a b =
	match a with
	| 0 -> b
	| _ -> gcd (b mod a) a

7.

Írja le a hátizsák feladat megoldására tanult algoritmust!

def knapsack(items, M):
	A = [0 for _ in range(M)]
	for item in items:
		for i in range(M, item.weight, -1):
			A[i] = max(A[i], A[i - item.weight] + item.value)
	return A[-1]

8.

Írja le Prim algoritmusát!

PSEUDOCODE

funtion prim(G, c):
  P = {1}; S = {}; M = V - {1}
  K[1] = 0
  T = {} // minimum spanning tree

  while P != {}:
      u = argmin{K[v] for v in P}
      P.remove(u)
      S.insert(u)

      if u != 1:
          T = T + {u, u.parent()}

      for v in u.neighbors():
          if v in P and c(u, v) < K(v):
              K(v) = c(u, v)
              p(v) = u

          if v in M:
              K(v) = c(u, v)
              p(v) = u
              M.remove(v)
              P.insert(v)
  return T
def prim(G, c):
    P, S, M = {0}, set(), G.vertices - {0}
    K = [float("inf") for _ in G.vertices]
    p = [-1 for _ in G.vertices]
    K[0] = 0
    T = set()  # the minimum spanning tree (set of edges)
 
    while len(P) != 0:
        u, _ = min([(v, K[v]) for v in P])
 
        P.remove(u)
        S.add(u)
 
        if u != 0:
            T.add((u, p[u]))
 
        for v in G.neighbors(u):
            if v in P and c(u, v) < K[v]:
                K[v] = c(u, v)
                p[v] = u
 
            if v in M:
                K[v] = c(u, v)
                p[v] = u
                M.remove(v)
                P.add(v)

9.

Írja le Dijkstra algoritmusát!

 PSEUDOCODE
 
 function dijkstra(G, s):
     P = {s}; S = {}; M = V - {s}; K[s] = 0; p(s) = s
     while P != {}:
         u = argmin(K(v) for v in P)
         P.remove(u)
         S.insert(u)

         for v in u.neighbors():
             if v in P and K[u] + c(u, v) < K[v]:
                 K[v] = K[u] + c(u, v)

             if v in M:
                 K[v] = K[u] + c(u, v)
                 p(v) = u
                 M.remove(v)
                 P.insert(v)

10.

Írja le Bellmann és Ford algoritmusát!

def BF(G, c):
	p = [0 for _ in range(n)]
	dist = [float('inf') for _ in range(n)]
	p, dist[s] = s, 0
	for i in range(n-1):
		for u in range(n):
			for v in u.neighbors():
				if dist[u] + c(u, v) < dist[v]:
					dist[v] = dist[u] + c(u, v)
					p[v] = u
 
	# test if change happens after n-1 iterations, if so, non conservative weights
	for u in range(n):
		for v in u.neighbors():
			if dist[u] + c(u, v) < dist[v]:
				p[v] = u
				return "non conservative", K, p, v
	return "conservative", K, p, s

11.

Írja le Johnson algoritmusát!

I. Futtassunk el egy Bellman-Ford algoritmust, mely ad nekünk egy megengedett pontenciált, azaz .

II. Módosítsuk az élek súlyozását a következő módon:
Ez a súlyozás már nemnegatív lesz, mert egy megengedett potenciál, ami pont azt jelenti, hogy a jobb oldal nem kisebb, mint .

III. Futtassunk minden csúcsból Dijkstra algoritmust a súlyozás szerint

IV. Vakarjuk ki a végeredményből a kívánt eredményt a következő módon:
Ha a legrővidebb szerinti út hossza és között, akkor ) a legrövidebb szerinti út hossza és között.

12.

Írja le azt az algoritmust, amely legrövidebb utat keres tetszőleges súlyozású irányított aciklikus gráfban! Feltehető, hogy minden csúcs elérhető -ből, és hogy a topologikus sorrendet már meghatároztuk.

def acikl_dijkstra(G):
	TS = G.topsort()
	P = [s]
	seen = []
	M = V - {s}
	dist[s] = 0
	p[s] = s
	for i in range(n):
		u = TS[i]
		P.remove(u)
		seen.add(u)
		for v in u.neighbors():
			if v in P and dist[u] + c(u, v) < dist[v]:
				dist[v] = dist[u] + c(u, v)
				p[v] = u
			if v in M:
				dist[v] = dist[v] + c(u, v) 
				p[v] = u
				M.remove(v)
				P.add(v)

Topologikus sorrend alapján iterálunk
Ha már vizsgált akkor megpróbáljuk frissíteni
Ha még nem vizsgált akkor inicializáljuk

related: AlgTerv 1