Python'da birleştirme
Birleştirme sıralaması uygulamam şu anda çok uzun sürüyor, 1 milyon öğeli bir liste için listenin sıralanması 130 saniyeden fazla sürüyor.
Birisi koduma nazikçe bakıp onu geliştirmek için ne yapabileceğimi önerebilir mi?
Kodumda önemli ölçüde uzun süren belirli bir şey var mı?
Kod
def splitlist(L): #splits the list to a list of individual listed elements (e.g. [1,2] to [[1],[2]])
envelop = lambda x: [x]
return(list(map(envelop,L)))
def merge(L_1,L_2): #merges two (already sorted) lists to one sorted list
N = []
while len(L_1) > 0 and len(L_2) > 0:
if L_1[0] > L_2[0]:
N += [L_2.pop(0)]
else:
N += [L_1.pop(0)]
if len(L_1) == 0:
N += L_2
else:
N += L_1
return(N)
#performs one round of pairwise merges (e.g. [[2],[1],[4],[3]] to [[1,2],[3,4]]), or [[5,10],[1,8],[2,3]] to [[1,2,3,5,8,10]])
def mergelist(L):
N = []
if len(L) % 2 == 0:
for i in range(0,len(L)//2):
N += [merge(L[2*i],L[2*i + 1])]
else:
for i in range(0,len(L)//2 - 1):
N += [merge(L[2*i],L[2*i + 1])]
N += [merge(merge(L[-3],L[-2]),L[-1])]
return(N)
def mergesort(L): #recursively performs mergelist until there is only 1 sorted list remaining
L = splitlist(L)
while len(L) > 1:
L = mergelist(L)
return(L[0])
Milyon elementi oluşturmak için benim kodum:
rlist = random.sample(range(0,2000000),1000000)
Yanıtlar
pop(0)Lineer zaman alır. Bunu O (1) zamanında farklı şekilde yapın. Standart yol, dizin değişkenlerini kullanır. Daha fazla pitonik yol için bu sorunun yanıtlarına bakın. Ya da kullanarak sağdan sola birleştirebilir pop()ve sonunda reverse()sonucu elde edebilirsiniz.
İkincisini yapmanın bir yolu:
def merge(L1, L2):
"""Merges two (already sorted) lists to one sorted list."""
N = []
while L1 and L2:
L = L1 if L1[-1] > L2[-1] else L2
N.append(L.pop())
N.reverse()
N[:0] = L1 or L2
return N
Yaptığım ve kodunuzun diğer bölümlerine de uygulayabileceğiniz diğer değişiklikler:
- Altçizgileri değişkenlerden kaldırdık, daha iyi okuduğunu düşünüyorum. Onlara çünkü için büyük harf tuttu
Len neyi olduğunu, PEP 8 söylüyor . Ve sonraNtutarlılık için tuttum . Genellikle kullanırdımresultya da belkimerged. Neden seçtiğini bilmiyorumN. "N" ile başlayan anlamlı bir kelimeniz varsa, onu kullanmanızı öneririm. - İşlev parametreleri arasındaki boşluk.
- Yorum yerine uygun belge dizesi biçimi.
- Değiştirilen
len(L_1) > 0Normal ileL1olmayan boşluk çek. N += [x]Normal ile değiştirildiN.append(x).
Başka bir yol, Ldaha net ama daha yavaş bir yolla belirlemek için bu "uzun" çizgiyi değiştirmek :
def merge(L1, L2):
"""Merges two (already sorted) lists to one sorted list."""
N = []
def last(L):
return L[-1]
while L1 and L2:
L = max(L2, L1, key=last)
N.append(L.pop())
N.reverse()
N[:0] = L1 or L2
return N
Biraz eğlence için, iki liste anlama hilesi:
def merge(L1, L2):
"""Merges two (already sorted) lists to one sorted list."""
def end(L):
return L[-1:]
return [max(L2, L1, key=end).pop() for _ in L1 + L2][::-1]
def merge(L, R):
"""Merges two (already sorted) lists to one sorted list."""
return [(R, L)[L[-1:] > R[-1:]].pop() for _ in L + R][::-1]
Ve çok daha hızlı bir yol olmadan ayrılmak istemiyorum:
def merge(L1, L2):
"""Merges two (already sorted) lists to one sorted list."""
return sorted(L1 + L2)
Bu, Timsort yüzünden O (n). Ve C kodu nedeniyle hızlı O (n). Bir birleştirme sıralaması sortediçinde güçlü olanı kullanmanın ilk etapta birleştirme sıralaması yazma amacını bozduğunu düşünüyorsanız : Bu bile, eğer sadece birleştirme sıralaması yapmıyorsanız, anlamlı olabilir. En azından bir kez, bir şeyin gömülü sayımıyla bir birleştirme sıralaması yazdım ve aslında sortedsadece birleştirme için kullandım . Çünkü bu, çözümümü daha hızlı / daha kısa / daha basit hale getirdi.
Daha da verimli (hem uzay hem de zaman):
def merge(L1, L2):
"""Merges two (already sorted) lists to one sorted list."""
L1 += L2
L1.sort()
return L1
(Eğer L2daha uzun olabilir L1, eklemek avantajlı olabilir L1içine L2yerine).