Byla vydána nová major verze 7.0 živé linuxové distribuce Tails (The Amnesic Incognito Live System), jež klade důraz na ochranu soukromí uživatelů a anonymitu. Nově je postavena je na Debianu 13 (Trixie) a GNOME 48 (Bengaluru). Další novinky v příslušném seznamu.
Společnost Meta na dvoudenní konferenci Meta Connect 2025 představuje své novinky. První den byly představeny nové AI brýle: Ray-Ban Meta (Gen 2), sportovní Oakley Meta Vanguard a především Meta Ray-Ban Display s integrovaným displejem a EMG náramkem pro ovládání.
Po půl roce vývoje od vydání verze 48 bylo vydáno GNOME 49 s kódovým názvem Brescia (Mastodon). S přehrávačem videí Showtime místo Totemu a prohlížečem dokumentů Papers místo Evince. Podrobný přehled novinek i s náhledy v poznámkách k vydání a v novinkách pro vývojáře.
Open source softwarový stack ROCm (Wikipedie) pro vývoj AI a HPC na GPU od AMD byl vydán ve verzi 7.0.0. Přidána byla podpora AMD Instinct MI355X a MI350X.
Byla vydána nová verze 258 správce systému a služeb systemd (GitHub).
Byla vydána Java 25 / JDK 25. Nových vlastností (JEP - JDK Enhancement Proposal) je 18. Jedná se o LTS verzi.
Věra Pohlová před 26 lety: „Tyhle aféry každého jenom otravují. Já bych všechny ty internety a počítače zakázala“. Jde o odpověď na anketní otázku deníku Metro vydaného 17. září 1999 na téma zneužití údajů o sporožirových účtech klientů České spořitelny.
Byla publikována Výroční zpráva Blender Foundation za rok 2024 (pdf).
Byl vydán Mozilla Firefox 143.0. Přehled novinek v poznámkách k vydání a poznámkách k vydání pro vývojáře. Nově se Firefox při ukončování anonymního režimu zeptá, zda chcete smazat stažené soubory. Dialog pro povolení přístupu ke kameře zobrazuje náhled. Obzvláště užitečné při přepínání mezi více kamerami. Řešeny jsou rovněž bezpečnostní chyby. Nový Firefox 143 bude brzy k dispozici také na Flathubu a Snapcraftu.
Byla vydána betaverze Fedora Linuxu 43 (ChangeSet), tj. poslední zastávka před vydáním finální verze, která je naplánována na úterý 21. října.
Tak už jsem dlouho nenapsal žádný blog, tak jsem se rozhodl, že spojím užitečné se zábavou. Takže jelikož jsem v poslední době byl někým žádán abych mu poskytl svůj program pro názorný výpočet determinantu (Python a PyQt vše je v dokumentaci), tak ho vložím i sem. Třeba se to taky někomu bude hodit. Dál se pokusím najít Salxeso (pexeso psané v Javě, samozřejmě psané jako semestrálka, takže to není žádný zázrak) do kterého mi tady někdo taky dělal hrací karty.
A teď se konečně dostáváme k věcem, na které jsem se zdejších odborníků chtěl zeptat, zda jsou vůbec proveditelné. Takže dostali jsme za úkol na C/C++ abychom napsali spojoví seznam. Na tom není nic těžkého podmínky byly jasně stanoveny, aby byl jednosměrný a aby obsahoval určité metody a to konkrétně: head(), first(), last(), isEmpty(), popFront(), pushFront(SItem), pushBack(SItem), insertAfter(SHandle *, SItem), concat(SList *), makeEmpty,moveAfter(SHandle *,SHandle *), moveToFront(SHandle *), moveToBack(SHandle *), remove(SHandle *). Na tom by nebylo nic složitého, ale máme další podmínku a to aby tyto metody měli konstantní časovou složitost, ale zde již narážím. Skoro všechny metody lze udělat s konstantní časovou složitostí ale pouze s dvousměrným seznamem (alespoň se tak domnívám). Konkrétně mi jde o tyto metody: insertAfter(SHandle *, SItem), makeEmpty, moveAfter(SHandle *,SHandle *), moveToFront(SHandle *), moveToBack(SHandle *), remove(SHandle *). U těchto metod totiž potřebujeme vědět předchůdce objektu (prvku) a jedinou možností, která mě napadá je si celý seznam projít a nalézt hledaného předchůdce, tudíž se dostáváme na časovou složitost algoritmu O(n). Navíc třeba metoda makeEmpty, která má celý spojoví seznam zahodit nelze v C++ realizovat, pokud používáme dynamické přidělování paměti, protože by nám objekty zůstali vyset v paměti, ale nevím jestli se i tohle počítá do časové složitosti toho algoritmu, ale řekl bych, že ano.
Tak co jaký názor na to mát? Myslíte si někdo, že to půjde, nebo je to pouze špatně zadané? Nebo jsem úplný blbec (to jsem )?
Tiskni
Sdílej:
IMHO se ty operace dají udělat i s jednosměrně zřetězeným seznamem v konstantním čase, jenom to neni zrovna obvyklé řešení (to s "přesměrovánim" ukazatelů).
Operaci vyjmout prvek lze totiž udělat i tak, že si zapamatuješ "obsah" prvku a ten nahradíš "obsahem" jeho následníka (včetně ukazatele na následující prvek).
2) Nepůjde smazat poslední prvek. I kdyby typ datové položky měl nějakou speciální "prázdnou" hodnotu, nebude jak správně aktualizovat ukazatel na konec seznamu, který je potřeba pro jiné operace.
Místo ukazatele na poslední prvek seznamu můžeš udržovat ukazatel na předposlední prvek.
?! Ukazatel na předposlední prvek si právě budeš pamatovat. A jestli si myslel "poslední" místo "předposlední", tak k tomu se z předposledního lehce dostaneš v konstantnim čase...
Máš pravdu, teorie s předposlednim prvkem je blbost. Nicméně by to mělo jít udělat přes "fixní" poslední prvek seznamu. Tzn. poslední prvek seznamu by byl "speciální" prvek, který by se nikdy nemazal.
Myslim to tak, že ten poslední prvek nebude navenek součástí seznamu. Seznam prostě pro N "uživatelskejch" prvků bude mít interně N + 1 prvků.
insertAfter(SHandle *, SItem), makeEmpty, moveAfter(SHandle *,SHandle *), moveToFront(SHandle *), moveToBack(SHandle *), remove(SHandle *). U těchto metod totiž potřebujeme vědět předchůdce objektu (prvku)Předpokládám, že předchůdce je právě ten první parametr. Čili hledat ho nepotřebuješ:
insertAfter(SHandle *item, SItem) {item->next = /*novej prvek*/;}
moveToFront
je jednoduché.remove
konstatně moc nejde, leda že bys hodnotu následujícího překopíroval do toho k odebrání, napojil ten následující za následujícím a uvolnil následující.moveToBack
a moveAfter
imho konstatně nepůjdou.makeEmpty
nevím co znamená, ale jestli to zahrnuje uvolňování paměti všech, konstatní složitost to určitě mít nebude...
moveToFront
vlastně jednoduché není, ledaže bys zase přehazoval hodnoty, což by se týkalo všech move*
a pak by to bylo konstatní.
že se ten další prvek nakopíruje na místo prvku, který chci přesunout.Jj, tak jsem to myslel. Dalo by se to udělat tak, že bys ty hodnoty do toho seznamu nevkládal přímo, ale přes pointer - "kopírování" by pak bylo jednoduchý. Ono s nějakým nasazením třeba templatů nebo něčeho by to v podstatě takhle dopadlo tak jako tak...
Taky to jde, když pro seznam použiješ jeden "buffer" (kterej budeš třeba exponenciálně zvětšovat) a nebudeš alokovat paměť pro každý prvek zvlášť.
Správnou odpověď ti dá asi jenom zadavatel, tedy cvičící. Já bych to tipoval, že operace smazat seznam konstantní bejt nemusí, jenom to neni v zadání explicitně napsaný. V nejhoršim případě můžeš prostě jenom "vynulovat" ukazatel na začátek seznamu a argumentovat tim, že o uvolňování paměti se v zadání nic nepíše .
prvky alokované, ale jinak úplně na h*vn*, v případě že budeš chtít alokovat, tak můžeš mrknout do toho druhého seznamu a prvky už alokované jen znova přidělíš a ještě si do toho napíšeš nějakou čistící rutinu, která po nějaké časové periodě mrkne do toho druhého seznamu a pokud v něm bude nějaký prvek, tak ho podle pointerů projede a celý uvolní. U procedur z vnějšího rozhraní dodržíš zadání a jak se to dělá uvnitř už nikoho nemusí zajímat.
Ale to makeEmpty konstantně nejdeJde, ale ne standardní alokaci paměti. Je třeba použít jiný typ alokace, tj. buď si jí dělat osobně (např. přes
mmap()
), nebo použít nějaký hiearchický alokator, jako třeba obstack nebo talloc. Když pak chcete zahodit celý seznam, tak stačí jen zrušit kontajner, ve kterém jsou jednolivé objekty alokovány.
mmap()
má konstantní časovou složitost, což (1) Vám nikdo neslibuje, (2) není pravda.
mmap()
uje /dev/zero
, což je metoda, jakou používají používají i standardní knihovny (vedle brk()
/sbrk()
). Za optimálních podmínek je odmapování otázka jediného volání jádra, takže v praxi nemá uživatelský program stejně žádnou rychlejší metodu, jak navrátit paměť operačnímu systému.
V moderních OS je dokonce možné ještě dále snížit režii jádra použitím stránek větších než 4KB (běžně 1MB, u nejnovějších procesorů až 1GB), což má i kladný vliv na rychlost přístupu k této paměti (lepší využitím TBL cache). V ultimativním případě se dá celá komplikovaná struktura uvolnit v čase velmi blízkém O(1), tedy pokud se do takovéto olbřímí stránky vejde celá.
Bohužel opravdu konstantí časová složitost opravdu zajistit nejde, ale dá se jí dost přiblížit zamknutím stránek v paměti a naplánování se jako realtime proces. Jenže pravé realtimové procesy stejně většinou nepoužívají klasickou dynamickou alokaci, buď mají všechny struktury statické, nebo přidělují bloky pevné velikosti.
mmap()
zdaleka nezávisí jenom na stránkách, ale (zrovna v případě Linuxu, jiné systémy na tom jsou podobně) i na režii VMA-listů, které mají logaritmickou složitost vzhledem k počtu prvků – jsou to ve skutečnosti vyhledávací stromy, protože je potřeba umět pro nový blok paměti najít volné místo v adresním prostoru. Zamykání stránek od toho nepomůže.
Implementujte třídy SHandle, SItem a SList, reprezentující prvky jednosměrně zřetězeného seznamu. SList - samotný spojový seznam, SHandle - ukazatel na SItem, SItem - prvek seznamu Implementujte operace pro SList head(), first(), last(), isEmpty(), popFront(), pushFront(SItem), pushBack(SItem), insertAfter(SHandle *, SItem), concat(SList *), makeEmpty,moveAfter(SHandle *,SHandle *), moveToFront(SHandle *), moveToBack(SHandle *), remove(SHandle *) s konstantní složitostí a findNext(SItem *, SHandle *) se složitostí O(n).
found=false;
for (c=str;*c; c++)
if (*c=='a')
{
found=true;
}
for (c=str;*c;c++)
if (*c=='a')
{
found=true;
break;
}
printf("found %d\n",found);
if next == end free (end); end = this; end;to ti zaruci, ze spojak stale ukazuje spravne.
def remove (link) if link.next == List.last data = link.data List.last = link else #normalni remove end return data end
To přece není až tak složité. Trik je v rozdílu mezi SHandle
a SItem
.
SHandle
je datová struktura pro uživatele transparentní; je to nějaký pointer do seznamu, s nímž uživatel nebude nic provádět, jen ho může podstrčit tomu API. (Tedy obdoba C++ iterátoru.) Takové věci se většinou ve veřejných headerech nechávají jako incomplete type, aby se je nikdo nesnažil nějak „instanciovat“ nebo kopírovat. (Ale to není podstatné.)
No a když mám přímo pointer na prvek toho seznamu, je implementace insertAfter(SHandle *, SItem)
v O(1) triviální.
Pro jednoduchost (a odstranění zbytečných if
ů) je dobré mít v seznamu vždy alespoň jeden prvek, tedy jakousi hlavu, která v případě prázdného seznamu bude ukazovat sama na sebe. Implementaci to výrazně zjednoduší. A co je ještě důležitější — umožní to navíc implementaci insertBefore(SHandle *, SItem)
v O(1). Struktura SHandle
jednoduše nebude ukazovat přímo na referencovaný prvek seznamu, ale na jeho předchůdce. Implementace insertBefore()
i insertAfter()
v O(1) je pak snadná.
Ještě jednou základní pointa:
insertAfter(SItem where, SItem newItem)
lze u seznamu provést pouze v O(n).insertAfter(SHandle * where, SItem newItem)
lze provést v O(1).insertBefore()
platí totéž.Zapomněl jsem to explicitně napsat, ale požadované moveAfter()
, moveBefore()
, moveToBack()
či moveToFront()
se vyřeší obdobným způsobem. Když potřebuješ znát předchůce, ukazuj prostě pomocí SHandle *
na předchůce a ne přímo na referencovaný prvek.