Stát Kalifornie zažaloval výrobce 3D tiskových filamentů Polymaker. Vrchní soud San Diego County tvrdí, že firma propagací svých výrobků mezi příznivci 3D tištěných zbraní podporovala výrobu takzvaných 'ghost guns' (DIY zbraní) a že její PLA filament pro 3D tiskárny lze za těchto okolností považovat za součást určenou k výrobě střelné zbraně. Žaloba požaduje mimo jiné finanční sankce a soudní zákaz činnosti, Polymaker se hájí tím, že filament je běžný a sám o sobě legální produkt. Celý text žaloby (PDF na Google Drive).
V červnu byla představena aplikace Myna pro převod řeči na text v prostředí desktopu Ubuntu. Včera byla Myna zpřístupněna širší komunitě Ubuntu formou technologické ukázky dostupné v Ubuntu 24.04 LTS, Ubuntu 26.04 LTS a Ubuntu 26.10 s GNOME na Waylandu.
Ubuntu 27.04 bude Tenacious T-Rex.
Byla vydána nová verze 2026.4.0 "Never-slop" svobodného softwaru ScummVM (Wikipedie) umožňujícího bezproblémový běh mnoha klasických adventur na zařízeních, pro které nebyly nikdy určeny. Přehled novinek v poznámkách k vydání a na GitHubu. ScummVM oslavil 25 let. Verze 0.0.1 vyšla 8. října 2001.
Kanadský vývojář Anthony Sistilli vytvořil ironický DIY projekt parodující kamerové systémy Flock, s cílem názorně demonstrovat rizika masového sledování jaké provozují tyto komerční ALPR systémy. Z levné IP kamery a vlastního ML softwaru (napsaného s pomocí SI circa za 20 minut, kód se mi bohužel nepodařilo dohledat) běžícího v laptopu sestavil jednoduchý systém, který detekuje výhradně policejní vozidla, zaznamenává jejich SPZ a
… více »Část údajů uživatelů internetového supermarketu Rohlík byla odcizena. Kyberútočníci napadli nástroj zákaznické podpory Rohlíku, odcizili tak jména, e-mailové adresy, v některých případech také telefonní čísla nebo přepisy komunikace mezi klienty a zákaznickou podporou. Rohlík incident nahlásil příslušným orgánům a přijal příslušné opatření, aby zamezil podobným případům v budoucnosti, uvedla firma.
Aplikace eDoklady fungovala v obou volebních dnech stabilně a prakticky bez front. Digitální a informační agentura (DIA) odhaduje, že se digitálním dokladem prokázalo více než 100.000 voličů. Aplikaci si před volbami či během nich aktualizovalo 247.517 uživatelů. Nových registrací bylo 19.431 a do aplikace se přihlásilo 357.879 lidí. Největší nápor přišel bezprostředně po otevření volebních místností mezi 14. a 16. hodinou, kdy si
… více »Začal semestr, začal i podzim a kromě hub rostou jako po dešti i veřejné dílny v Praze. Nedávno strahováci referovali o hackerspacu Bordel, nyní se otevřela dílna Dejvice Lab jen kousek od ČVUT. Na blížící Virtuální Bastlírně tak uslyšíte nejen report z návštěvy dílny HWLab, ale i řadu novinek, událostí a úsměvných momentů, které se za poslední měsíc ve světě techniky, ale i vědy udály. Připojte se tedy již v úterý 13.10. od 20:00 a zapojte se do
… více »Byl vydán LineageOS 24 (Mastodon). LineageOS (Wikipedie) je svobodný operační systém pro chytré telefony, tablety a set-top boxy založený na Androidu. Jedná se o nástupce CyanogenModu. LineageOS 24 je založený na Androidu 17.
Společnost Valve publikovala na svém GitLabu nákresy a schémata zapojení headsetu Steam Frame. Pro nekomerční účely.
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).
tak by to šlo.
, protože tam mám ukazatele na ty prvky, takže je stačí jenom prohodit a nemusím nic kopírovat. Takže dík.
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...
takže jsem to měl už připravené jenom jsem to upravil
.
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
.
.
a nebo si ten Garbage collector můžeš implementovat sám. Udělat ještě jeden seznam 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.