Array implementation of Stack

M

Michael Press

Willem said:
Keith Thompson wrote:
) Willem, you have a point. There is no One True Way to define the
) set of operations available for a stack.

Thank you, that was exactly the point I was trying to make.

) On the other hand, some operations make sense and some do not.
)
) I don't believe you've demonstrated that a push() operation that
) extends the stack without storing a value in the top element makes
) any sense.

I never tried to demonstrate it. I just got very annoyed by people
claiming that thier views on stacks are the One True Way, and using
bad logic to argue their points.

Nobody tried to argue *why* it maked sense to have the stack operations
work the way they say they should work. They just *asserted* it.

) Under what circumstances would you want to use such an operation?
) As far as I can see, extending the stack is *always* immediately
) followed by storing a value in the new top element. How would it
) be advantageous to separate those operations?

The most obvious one would be is your application needs a way to replace
or change the top value of a stack. Then a push() which sets the value
also would be redundant(*).

Another one would be if the 'value' on the stack is actually a large
entity, such as a struct, and passing the whole struct would be
a performance issue, especially if you're only using a part of it.

This is especially true if the stack is a way of being able to step
back to a previous saved state.

As a real-life example of that, look at a postscript interpreter, which
keeps a stack of graphics contexts. Or a chess playing program, which
needs to save the current state of the board to be able to try different
moves.


Another example would be when growing the stack would be a very costly
operation, and putting items in slots very cheap. In that case, it would
be very advantageous if you could grow the stack by a large step, and
then insert all the items one by one.

One could also imagine having a stack that stores char values, but using it
for different-sized objects/blobs.


Oh, and as a very real-life example, look at the way that a C compiler uses
stack frames: it allocates a whole frame in one go, and then uses the space
it created for different variables, objects, et cetera.

A stack frame is best conceptualized as a single push. The
details are not a stack operation at all. The details are
memory allocation and initialization. _In_ the stack frame is
data that tells the supervising process how to get the value of
the stack pointer after this stack frame is released---how to
pop the stack.
 
N

Nick Keighley

pop() not returning a value makes some sense if you think that
shrinking the stack and retrieving the top element should be
separate operations.

for instance C++'s STL does it taht way
 
L

luser- -droog

Ben said:
This is an expression of void type but top() returns an item. That's
what my point was all about. Note that I do use the value of the
assignment so I must be remembering that it returns one!


Without the comma, you don't have an expression that behaves like top().

Oh. I get it now. You're squeezing it into an expression. It appears
my
inclination is to break this into multiple statements.

So, the awkwardness *is* necessary for the expressivity you describe.
 
L

luser- -droog

Just for drill I looked up what Knuth had to say in section 2.2.1 on
stacks, queues, and dequeues.  He talks a good deal about push and pop
and various equivalent nomenclatures.  Unless I missed it he doesn't
mention a top command at all until the last paragraph that reads:

    When A is a nonempty stack, we MAY (emphasis mine) write

        top(A)

    to denote its top element.

I do not wish to appeal to authority, but in my experience Knuth's
depiction of stacks is the norm and Rui's formulation is
idiosyncratic.  In short, push and pop are fundamental; top is a
convenience but it is not fundamental.  

The 'nonempty' part seems tricky. If push() and pop() are used in
pairs,
one could avoid underflow checking entirely. But top() appears to need
an error mechanism, that might otherwise be omitted.
This is not to say that one can't come up with alternative commands.
For example one could have advance(), retreat(), write(item), and
read(), where write overwrites the top slot, read reads the top slot,
retreat moves the stack position back one slot, and advance moves it
forward one slot provided that the existing top slot isn't empty.

The suite of fanciful alternatives can be extended almost
indefinitely.

That might do well for a lower-level interface to the same object.
Then the stack interface could use these APIs to implement push(),
pop(), and top().
 
K

Kleuskes & Moos

"Kleuskes & Moos" <[email protected]> ha scritto nel messaggio#io_x

Nitpick to an otherwise excellent expose:

That works fine if the content of your stack consists of simple values
(int, floats and such), you get into trouble when the stack consists
of structures. You can't just return a pointer, since the structure
will b ''destroyed'' with a pop operation.
---------------
#yes for stack of structures, not for stack of pointers to structs
#
#char  *a;
#...
#a=pop(stack); if(a==0) error();
#// a point to the struct or 0
#free(a);
#

Having noted your corrigendum, and noting that a pointer is a "simple"
value, i still have a few problems with the above code. So let's
pretend to do a code review.

1) NULL might be stored quite legally on the stack, thus generating an
error when popping it off does not seem appropriate.

2) Assuming the code above is intended to fail on an empty stack, it
should fail _in_ the pop(stack) call, triggered by an inspection of
ToS. not afterwards.

3) If the code is supposed to fail _in_ pop, returning a proper error
code ('ERROR_STACK_EMPTY' or somesuch), seems to be appropriate, thus
preventing the pop-implementation to return any content.
 
B

Ben Bacarisse

Stephen Sprunk said:
In theory, I agree. However, are there implementations where returning
a value the function _already has available_ has a non-negligible
resource (I assume memory or CPU) impact?

I don't know. It must have some impact, but I have no idea if it can
ever be counted as significant. I can say that I've never changed a
function's return type to void in order to gain some performance
advantage, but that's not a "fair" observation -- functions with return
values end up having that value used, so changing the interface so that
the function does not return a value is usually far from trivial, so it
is rarely going to be an appealing target for micro-optimisation.
 
K

Kleuskes & Moos

Rui Maciel said:
Willem wrote:
[...]

Again, do you even know what a stack is?  If you don't know, I can tell you
that a stack is a LIFO data structure.  A stack, by it's very definition,
doesn't offer a way to traverse the data structure.  It offers a way for you
to access the top() element, it lets  you push() elements and it letsyou
pop() elements.  If you are thinking of a data structure which lets you
traverse the data it stores then you are thinking of some other data
structure, but you aren't thinking of a stack.

[I'm not quoting anything Willem wrote, but keeping the attribution line
to make it clear whom Rui is addressing.]

So if I showed you an interface that provides only the following
operations:

    void push(item x); // pushes x onto stack
    item pop(void);    // removes top element from stack and
                       // returns its value

you'd tell me that it's not a stack, because it doesn't directly provide
a "top" operation?

Depending on the usage, i might give you a hard time about that in a
code/design review and call the implementation "incomplete", unless
you can guarantee

a) the top-item is never inspected apart from after a 'pop'
b) the stack is never empty or you have a good definition for an error-
value of 'item'.
c) the stack is never 'full'.

In some cases, the above is all you need, but they are the exception,
rather than the rule.
 
N

Nick Keighley

Just for drill I looked up what Knuth had to say in section 2.2.1 on
stacks, queues, and dequeues.  He talks a good deal about push and pop
and various equivalent nomenclatures.  Unless I missed it he doesn't
mention a top command at all until the last paragraph that reads:

    When A is a nonempty stack, we MAY (emphasis mine) write

        top(A)

    to denote its top element.

I do not wish to appeal to authority, but in my experience Knuth's
depiction of stacks is the norm and Rui's formulation is
idiosyncratic.  In short, push and pop are fundamental; top is a
convenience but it is not fundamental.  

This is not to say that one can't come up with alternative commands.
For example one could have advance(), retreat(), write(item), and
read(), where write overwrites the top slot, read reads the top slot,
retreat moves the stack position back one slot, and advance moves it
forward one slot provided that the existing top slot isn't empty.

The suite of fanciful alternatives can be extended almost
indefinitely.-

http://en.wikipedia.org/wiki/Stack_(data_structure)

they include a top operation. As does C++s STL





<spoiler>


ok I admit it, I wrote part of the wiki page
 
W

Willem

Michael Press wrote:
) A stack frame is best conceptualized as a single push. The
) details are not a stack operation at all. The details are
) memory allocation and initialization. _In_ the stack frame is
) data that tells the supervising process how to get the value of
) the stack pointer after this stack frame is released---how to
) pop the stack.

Thus illustrating my point nicely: It's a push without setting the value.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
K

Keith Thompson

Kleuskes & Moos said:
Rui Maciel said:
Willem wrote:
[...]

Again, do you even know what a stack is?  If you don't know, I can tell you
that a stack is a LIFO data structure.  A stack, by it's very definition,
doesn't offer a way to traverse the data structure.  It offers a way for you
to access the top() element, it lets  you push() elements and it lets you
pop() elements.  If you are thinking of a data structure which lets you
traverse the data it stores then you are thinking of some other data
structure, but you aren't thinking of a stack.

[I'm not quoting anything Willem wrote, but keeping the attribution line
to make it clear whom Rui is addressing.]

So if I showed you an interface that provides only the following
operations:

    void push(item x); // pushes x onto stack
    item pop(void);    // removes top element from stack and
                       // returns its value

you'd tell me that it's not a stack, because it doesn't directly provide
a "top" operation?

Depending on the usage, i might give you a hard time about that in a
code/design review and call the implementation "incomplete", unless
you can guarantee

a) the top-item is never inspected apart from after a 'pop'
b) the stack is never empty or you have a good definition for an error-
value of 'item'.
c) the stack is never 'full'.

In some cases, the above is all you need, but they are the exception,
rather than the rule.

Ok, but that wasn't my question. Rui's argument seems to imply that
it's not a stack at all, not merely that it's not a very good interface.
 
K

Kleuskes & Moos

Willem wrote:
[...]
Again, do you even know what a stack is?  If you don't know, I cantell you
that a stack is a LIFO data structure.  A stack, by it's very definition,
doesn't offer a way to traverse the data structure.  It offers a way for you
to access the top() element, it lets  you push() elements and it lets you
pop() elements.  If you are thinking of a data structure which lets you
traverse the data it stores then you are thinking of some other data
structure, but you aren't thinking of a stack.
[I'm not quoting anything Willem wrote, but keeping the attribution line
to make it clear whom Rui is addressing.]
So if I showed you an interface that provides only the following
operations:
    void push(item x); // pushes x onto stack
    item pop(void);    // removes top element from stack and
                       // returns its value
you'd tell me that it's not a stack, because it doesn't directly provide
a "top" operation?
Depending on the usage, i might give you a hard time about that in a
code/design review and call the implementation "incomplete", unless
you can guarantee
a) the top-item is never inspected apart from after a 'pop'
b) the stack is never empty or you have a good definition for an error-
value of 'item'.
c) the stack is never 'full'.
In some cases, the above is all you need, but they are the exception,
rather than the rule.

Ok, but that wasn't my question.  Rui's argument seems to imply that
it's not a stack at all, not merely that it's not a very good interface.

A stack-implementation with a bad interface amounts to pretty much the
same as having no (usable) stack at all. For that reason i'd rather
side with Ruiz on that, demanding a proper interface to and
implementation of the generally accepted functionality of a stack,
than Willem, who seems to that that a stack can be implemented and
interfaced any which way.

The "Law of Least Surprize" is valid in these cases. Having some kind
of consensus of what you're talking about avoids much scratching of
ears, pointing at foreheads and general gnashing of teeth and loud
lamenting from the Upper Echelons.

At least that's my expirience.
 
K

Kleuskes & Moos

Michael Press wrote:

) A stack frame is best conceptualized as a single push. The
) details are not a stack operation at all. The details are
) memory allocation and initialization. _In_ the stack frame is
) data that tells the supervising process how to get the value of
) the stack pointer after this stack frame is released---how to
) pop the stack.

Thus illustrating my point nicely: It's a push without setting the value.

SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
            made in the above text. For all I know I might be
            drugged or something..
            No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
J

James Kuyper

On 06/24/2011 01:13 PM, Kleuskes & Moos wrote:
.....
The "Law of Least Surprize" is valid in these cases. Having some kind
of consensus of what you're talking about avoids much scratching of
ears, pointing at foreheads and general gnashing of teeth and loud
lamenting from the Upper Echelons.

You may have noticed a distinct lack of consensus on this thread.
When different people are surprised by different things, the "Law of
Least Surprise" breaks down as a design principle.
 
K

Kleuskes & Moos

On 06/24/2011 01:13 PM, Kleuskes & Moos wrote:
....


You may have noticed a distinct lack of consensus on this thread.
When different people are surprised by different things, the "Law of
Least Surprise" breaks down as a design principle.

Hmmm.. With all due respect to all those posting here, they do not
seem to be the average development team, but rather seem to argue for
the love of arguing. Nothing wrong with that, I do it myself
sometimes.

Nevertheless, introducing the designs as suggested in this thread (and
that includes the interfaces you brought up (and i do appreciate they
are not a sample of your usual design-style) need explanation, and
various people have expressed some surprise.

Hence the Law of Least Surprise works just fine. The fact that there
is no consensus here just shows this forum does not thrive on
consensus but conflict. That's in the nature of a discussion forum. If
people agree, it gets booooriiiiing pretty fast. No surprises there.
 
K

Kleuskes & Moos

// macro for function
#define  P  printf

// macro for keyWords
#define G  goto
#define R  return
#define W  while
#define F  for
#define T  template
#define TN typename

The above macro's ought to be taken out and shot.
 
J

James Kuyper

On 06/25/2011 02:00 AM, Kleuskes & Moos wrote:
....
Nevertheless, introducing the designs as suggested in this thread (and
that includes the interfaces you brought up (and i do appreciate they
are not a sample of your usual design-style) need explanation, and
various people have expressed some surprise.

Um ... - those were Keith's suggestions. I haven't made any.
 
K

Kleuskes & Moos

On 06/25/2011 02:00 AM, Kleuskes & Moos wrote:
...


Um ... - those were Keith's suggestions. I haven't made any.

X'cuse me. Errare humanum est, after all. Mutatis mutandis, i'll stick
with my statement, though.
 
P

Patrick Scheible

Kleuskes & Moos said:
The above macro's ought to be taken out and shot.

Especially G for goto. If you use gotos enough to need a macro for
them, you're doing something very, very wrong.

But all of them should go. Too cryptic to expect third parties to read,
not cryptic enough to win the obfuscated C contest.

-- Patrick
 
C

Chad

pop() gives you the top element, but it also has the side effect
of removing the top element from the stack.
Sometimes you want to look at the top element without modifying the stack..
If there isn't a separate top() operation, then of course

  dosomethingwith(top());

can be emulated by

  temp = pop(); push(temp); dosomethingwith(temp);

but the latter looks a bit awkward.


What I've sometimess seen people do is like the following..

/*Return and remove the top element from the stack*/
int pop() {
return elements[--size];
}

/*Return the top element from the stack*/
int peek() {
return elmenets[size - 1];
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,017
Latest member
GreenAcreCBDGummiesReview

Latest Threads

Top