To a certain extent, yes, it could be a waste of space. However, typically you won't have the same application in multiple places on the same machine.
Let's take an example of a program "MyProgram.exe" and a helper assembly "MyProgram.Helpers.dll". "MyProgram" is the programs namespace and "MyProgram.Helpers" is the DLL's namespace. When you run a MyProgram.exe, and that program to use a class from MyProgram.Helpers the framework will first look in the directory that the application is running for a library (DLL) that contains the "MyProgram.Helpers" namespace. If it doesn't find it there, it will then look in the GAC. (I believe there are ways of telling a program where else it can look for assemblies but I've never done it.) If the framework can't find the assembly it will throw an exception and tell you that it can't find a referenced assembly.
ASP.NET application are a little different. The execution directory of the application is the virtual directory established in IIS. Executable binaries must live inside the bin\ folder of the directory.
Assemblies that are commonly used such as those that make up the base .NET framework, are placed into the framework's Global Assembly Cache (GAC). Having an assembly in the GAC is kind of like registering it like you would a COM component. You can then reference an assembly namespace from anywhere on the computer. An important feature of the GAC is that it is aware of more than just the name of the assembly. The GAC can maintain several versions of the same assembly. Programs reference a specific version of a namespace in addition to the namespace. You can install version 1.0, 1.1 and 2.0 of the .NET framework on the same machine. When you build a program with version 1.1, the program references the 1.1 versions of the framework.