I try to implement a C interface using a Prolog script based on GNU Prolog. My problem is to get single elements of a nested Prolog list.
Actually my C code looks like
...
int func;
PlTerm arg[10];
PlTerm *sol_gb;
PlBool res;
int nmb;
char *strHead;
char *strTail;
PlLong nummero;
PlTerm pl_nummero;
Pl_Start_Prolog(argc, argv);
Pl_Query_Begin(PL_TRUE);
arg[0] = Pl_Mk_String(strRName);
arg[1] = Pl_Mk_Variable();
arg[2] = Pl_Mk_Variable();
arg[3] = Pl_Mk_String("true");
res = Pl_Query_Call(func, 4, arg);
sol_gb = Pl_Rd_List(arg[2]);
nmb = Pl_List_Length(sol_gb[0]);
strHead = Pl_Write_To_String(sol_gb[0]);
printf("strHead = %s\n",strHead);
strTail = Pl_Write_To_String(sol_gb[1]);
printf("strTail = %s\n",strTail);
...
The Prolog list returned in arg[2] looks like
[ [ Spezial Bolognese,
[2, ,Zwiebeln,300,gramm,Hackfleisch,10, ,Tomaten,
100,ml,Sahne,500,gramm,Spaghetti]
],
[ Spaghetti Bolognese,
[2, ,Zwiebeln gehackt,300,gramm,Hackfleisch,10, ,Fleischtomaten,
100,ml,Sahne,500,gramm,Spaghetti]
]
]
The output of the conversion into a String is
strHead = [Spezial Bolognese,[2, ,Zwiebeln gehackt,300,gramm,Hackfleisch,
10, ,Fleischtomaten,100,ml,Sahne,500,gramm,Spaghetti]]
strTail = [[Spaghetti Bolognese,[2, ,Zwiebeln gehackt,300,gramm,Hackfleisch,
10, ,Fleischtomaten,100,ml,Sahne,500,gramm,Spaghetti]]]
So I assume, I am "nearly there" but as I have to re-activate my C knowledge I do not get the solution how to enter in the next level of the list to get finally each element as string ("Spezial Bolognese", next step: "2", "Zwiebeln" etc.).
How can I step through the Prolog list in C?
I would be very happy about every hint, thank you again!
To get the content of a list from the C-code you can use 2 kind of functions.
First possibility (simple since the list is seen as a flat object but requires more memory and needs a proper list, i.e. does not work for lists not terminated by [])
int Pl_Rd_Proper_List_Check(PlTerm the_prolog_list, PlTerm *the_array_receiving_arguments);
this functions receives an array (it is up to you to ensure it is large enough), stores each element of the list in the array and returns the total number of elements. Example:
PlTerm list = ...some Prolog list...
int nElem = Pl_List_Length(list);
PlTerm *elem = (PlTerm *) calloc(nElem, sizeof(PlTerm));
Pl_Rd_Proper_List_Check(list, elem);
int i;
for(i = 0; i < nElem; i++) {
// here there is an argument in elem[i], let's print it
Pl_Write(elem[i]);
}
Second possibility (more general but see a list as a chained list, each cell contains the head and a tail (a list))
PlTerm *Pl_Rd_List(PlTerm the_prolog_list);
This function returns an array of 2 elements corresponding to the head and the tail of the received list. This function should be called on each element of the list; either you know the number of elements or you test the end of the list (e.g. waiting for the end of list atom []). Here is a code doing this (it is expected to be inside the above loop since we know the second argument of the list is a nested list.
PlTerm list = ... some Prolog list...;
while(!Pl_Un_Atom(Pl_Atom_Nil(), list)) {
PlTerm *lst_arg = Pl_Rd_List(list); // [0] = head element, [1] = tail list
// here there is an argument in lst_arg[0], let's print it
Pl_Write(lst_arg[0]);
list = lst_arg[1];
}
In your example, the first list looks like:
[ 'Spezial Bolognese',
[2,' ','Zwiebeln',
300,'gramm','Hackfleisch',
10,' ','Tomaten',
100,'ml','Sahne',
500,'gramm','Spaghetti']
]
so the second element is a nested list. The following code uses the first method for the above list (which has 2 elements), and the second method for the nested list:
nElem = Pl_List_Length(sol_gb[0]);
PlTerm *elem = (PlTerm *) calloc(nElem, sizeof(PlTerm));
Pl_Rd_Proper_List_Check(sol_gb[0], elem);
int i;
for(i = 0; i < nmb; i++) {
if (i != 1) {
Pl_Write(elem[i]);
printf("\n");
} else { // we know it is a list
printf("(");
PlTerm list = elem[i];
while(!Pl_Un_Atom(Pl_Atom_Nil(), list)) {
PlTerm *lst_arg = Pl_Rd_List(list); // [0] = head element, [1] = tail list
printf(" ");
Pl_Write(lst_arg[0]);
list = lst_arg[1];
}
printf(" )\n");
}
}
Here should be the output
Spezial Bolognese
( 2 Zwiebeln 300 gramm Hackfleisch 10 Tomaten 100 ml Sahne 500 gramm Spaghetti )
The sample code you give of the lists of lists sounds like a textbook example of a very bad choice for knowledge representation. I strongly suggest you change it to a more declarative representation. Something like:
% pizza(Name, Steps)
pizza('Spezial Bolognese', ...).
...
where Steps could be a list of step(...) terms. This would potentially make processing the information easier and more efficient. For example, in the Prolog side, you could then use the standard arg/3 predicate to access a specific element in a step. With lists, you have no choice other than traversing them every time you want an element other than the list head.
Related
For example, string "AAABBB" will have permutations:
"ABAABB",
"BBAABA",
"ABABAB",
etc
What's a good algorithm for generating the permutations? (And what's its time complexity?)
For a multiset, you can solve recursively by position (JavaScript code):
function f(multiset,counters,result){
if (counters.every(x => x === 0)){
console.log(result);
return;
}
for (var i=0; i<counters.length; i++){
if (counters[i] > 0){
_counters = counters.slice();
_counters[i]--;
f(multiset,_counters,result + multiset[i]);
}
}
}
f(['A','B'],[3,3],'');
This is not full answer, just an idea.
If your strings has fixed number of only two letters I'll go with binary tree and good recursion function.
Each node is object that contains name with prefix of parent name and suffix A or B furthermore it have numbers of A and B letters in the name.
Node constructor gets name of parent and number of A and B from parent so it needs only to add 1 to number of A or B and one letter to name.
It doesn't construct next node if there is more than three A (in case of A node) or B respectively, or their sum is equal to the length of starting string.
Now you can collect leafs of 2 trees (their names) and have all permutations that you need.
Scala or some functional language (with object-like features) would be perfect for implementing this algorithm. Hope this helps or just sparks some ideas.
Since you actually want to generate the permutations instead of just counting them, the best complexity you can hope for is O(size_of_output).
Here's a good solution in java that meets that bound and runs very quickly, while consuming negligible space. It first sorts the letters to find the lexographically smallest permutation, and then generates all permutations in lexographic order.
It's known as the Pandita algorithm: https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
import java.util.Arrays;
import java.util.function.Consumer;
public class UniquePermutations
{
static void generateUniquePermutations(String s, Consumer<String> consumer)
{
char[] array = s.toCharArray();
Arrays.sort(array);
for (;;)
{
consumer.accept(String.valueOf(array));
int changePos=array.length-2;
while (changePos>=0 && array[changePos]>=array[changePos+1])
--changePos;
if (changePos<0)
break; //all done
int swapPos=changePos+1;
while(swapPos+1 < array.length && array[swapPos+1]>array[changePos])
++swapPos;
char t = array[changePos];
array[changePos] = array[swapPos];
array[swapPos] = t;
for (int i=changePos+1, j = array.length-1; i < j; ++i,--j)
{
t = array[i];
array[i] = array[j];
array[j] = t;
}
}
}
public static void main (String[] args) throws java.lang.Exception
{
StringBuilder line = new StringBuilder();
generateUniquePermutations("banana", s->{
if (line.length() > 0)
{
if (line.length() + s.length() >= 75)
{
System.out.println(line.toString());
line.setLength(0);
}
else
line.append(" ");
}
line.append(s);
});
System.out.println(line);
}
}
Here is the output:
aaabnn aaanbn aaannb aabann aabnan aabnna aanabn aananb aanban aanbna
aannab aannba abaann abanan abanna abnaan abnana abnnaa anaabn anaanb
anaban anabna ananab ananba anbaan anbana anbnaa annaab annaba annbaa
baaann baanan baanna banaan banana bannaa bnaaan bnaana bnanaa bnnaaa
naaabn naaanb naaban naabna naanab naanba nabaan nabana nabnaa nanaab
nanaba nanbaa nbaaan nbaana nbanaa nbnaaa nnaaab nnaaba nnabaa nnbaaa
This is a tough one, at least for my minimal c skills.
Basically, the user enters a list of prices into an array, and then the desired number of items he wants to purchase, and finally a maximum cost not to exceed.
I need to check how many combinations of the desired number of items are less than or equal to the cost given.
If the problem was a fixed number of items in the combination, say 3, it would be much easier with just three loops selecting each price and adding them to test.
Where I get stumped is the requirement that the user enter any number of items, up to the number of items in the array.
This is what I decided on at first, before realizing that the user could specify combinations of any number, not just three. It was created with help from a similar topic on here, but again it only works if the user specifies he wants 3 items per combination. Otherwise it doesn't work.
// test if any combinations of items can be made
for (one = 0; one < (count-2); one++) // count -2 to account for the two other variables
{
for (two = one + 1; two < (count-1); two++) // count -1 to account for the last variable
{
for (three = two + 1; three < count; three++)
{
total = itemCosts[one] + itemCosts[two] + itemCosts[three];
if (total <= funds)
{
// DEBUG printf("\nMatch found! %d + %d + %d, total: %d.", itemCosts[one], itemCosts[two], itemCosts[three], total);
combos++;
}
}
}
}
As far as I can tell there's no easy way to adapt this to be flexible based on the user's desired number of items per combination.
I would really appreciate any help given.
One trick to flattening nested iterations is to use recursion.
Make a function that takes an array of items that you have selected so far, and the number of items you've picked up to this point. The algorithm should go like this:
If you have picked the number of items equal to your target of N, compute the sum and check it against the limit
If you have not picked enough items, add one more item to your list, and make a recursive call.
To ensure that you do not pick the same item twice, pass the smallest index from which the function may pick. The declaration of the function may look like this:
int count_combinations(
int itemCosts[]
, size_t costCount
, int pickedItems[]
, size_t pickedCount
, size_t pickedTargetCount
, size_t minIndex
, int funds
) {
if (pickedCount == pickedTargetCount) {
// This is the base case. It has the code similar to
// the "if" statement from your code, but the number of items
// is not fixed.
int sum = 0;
for (size_t i = 0 ; i != pickedCount ; i++) {
sum += pickedItems[i];
}
// The following line will return 0 or 1,
// depending on the result of the comparison.
return sum <= funds;
} else {
// This is the recursive case. It is similar to one of your "for"
// loops, but instead of setting "one", "two", or "three"
// it sets pickedItems[0], pickedItems[1], etc.
int res = 0;
for (size_t i = minIndex ; i != costCount ; i++) {
pickedItems[pickedCount] = itemCosts[i];
res += count_combinations(
itemCosts
, costCount
, pickedItems
, pickedCount+1
, pickedTargetCount
, i+1
, funds
);
}
return res;
}
}
You call this function like this:
int itemCosts[C] = {...}; // The costs
int pickedItems[N]; // No need to initialize this array
int res = count_combinations(itemCosts, C, pickedItems, 0, N, 0, funds);
Demo.
This can be done by using a backtracking algorithm. This is equivalent to implementing a list of nested for loops. This can be better understood by trying to see the execution pattern of a sequence of nested for loops.
For example lets say you have, as you presented, a sequence of 3 fors and the code execution has reached the third level (the innermost). After this goes through all its iterations you return to the second level for where you go to the next iteration in which you jump again in third level for. Similarly, when the second level finishes all its iteration you jump back to the first level for which continues with the next iteration in which you jump in the second level and from there in the third.
So, in a given level you try go to the deeper one (if there is one) and if there are no more iterations you go back a level (back track).
Using the backtracking you represent the nested for by an array where each element is an index variable: array[0] is the index for for level 0, and so on.
Here is a sample implementation for your problem:
#define NUMBER_OF_OBJECTS 10
#define FORLOOP_DEPTH 4 // This is equivalent with the number of
// of nested fors and in the problem is
// the number of requested objects
#define FORLOOP_ARRAY_INIT -1 // This is a init value for each "forloop" variable
#define true 1
#define false 0
typedef int bool;
int main(void)
{
int object_prices[NUMBER_OF_OBJECTS];
int forLoopsArray[FORLOOP_DEPTH];
bool isLoopVariableValueUsed[NUMBER_OF_OBJECTS];
int forLoopLevel = 0;
for (int i = 0; i < FORLOOP_DEPTH; i++)
{
forLoopsArray[i] = FORLOOP_ARRAY_INIT;
}
for (int i = 0; i < NUMBER_OF_OBJECTS; i++)
{
isLoopVariableValueUsed[i] = false;
}
forLoopLevel = 0; // Start from level zero
while (forLoopLevel >= 0)
{
bool isOkVal = false;
if (forLoopsArray[forLoopLevel] != FORLOOP_ARRAY_INIT)
{
// We'll mark the loopvariable value from the last iterration unused
// since we'll use a new one (in this iterration)
isLoopVariableValueUsed[forLoopsArray[forLoopLevel]] = false;
}
/* All iterations (in all levels) start basically from zero
* Because of that here I check that the loop variable for this level
* is different than the previous ones or try the next value otherwise
*/
while ( isOkVal == false
&& forLoopsArray[forLoopLevel] < (NUMBER_OF_OBJECTS - 1))
{
forLoopsArray[forLoopLevel]++; // Try a new value
if (loopVariableValueUsed[forLoopsArray[forLoopLevel]] == false)
{
objectUsed[forLoopsArray[forLoopLevel]] = true;
isOkVal = true;
}
}
if (isOkVal == true) // Have we found in this level an different item?
{
if (forLoopLevel == FORLOOP_DEPTH - 1) // Is it the innermost?
{
/* Here is the innermost level where you can test
* if the sum of all selected items is smaller than
* the target
*/
}
else // Nope, go a level deeper
{
forLoopLevel++;
}
}
else // We've run out of values in this level, go back
{
forLoopsArray[forLoopLevel] = FORLOOP_ARRAY_INIT;
forLoopLevel--;
}
}
}
I am trying to merge two binary trees and this is what I have come up with. I believe that my Insertmerge functions are correct as well as my and merge functions work...I am having trouble with my merge helper. I need to do is post order, left then right, but I am not sure if what I am doing makes sense. Any thoughts?
SparseNode * mergehelper(SparseNode* C_array_1, SparseNode * array_2)
{
if(array_2 ==NULL)
{
return(C_array_1);
}
C_array_1= SparseArray_InsertMerge(C_array_1, ((array_2->left)->index),((array_2->left)-
>value));
C_array_1= SparseArray_InsertMerge(C_array_1, ((array_2->right)->index),((array_2->right)->value));
}
SparseNode* SparseArray_InsertMerge(SparseNode * array, int index, int value)
{
check(array);
if(array ==NULL)
{
return SparseNode_create(index, value);
}
if((array->index)==index)
{
if(array->value == -value)
array= SparseArray_remove (array, array->index);
else
array->value += value;
check(array);
return array;
}
if((array->index)>index)
{
array->left = SparseArray_insert(array->left, index, value);
}
if((array->index)<index)
{
array->right = SparseArray_insert(array->right, index, value);
}
check(array);
return array;
}
/*
post order traversal
new insert for merge
adapt for nonoverwriting
do a tree traversal
then add the node into the copied list in the work of the tree traversal
in merge. copy array1. call mergehelper with copy.
in helper. if null return, then insert left and insert right. print function is similiar
*/
SparseNode * SparseArray_merge(SparseNode * array_1, SparseNode * array_2)
{
SparseNode*Arr1_copy = copy(array_1);
Arr1_copy = mergehelper(Arr1_copy, array_2);
return (Arr1_copy);
}
The easiest way to merge two binary trees is to simply use the functionality that the trees already provide:
a traversal, extracting the values.
a means of inserting values.
So the solution then becomes (pseudo-code):
def mergeTrees (tree1, tree2):
valuePtr = tree2.getFirst();
while valuePtr != NULL:
tree1.addNode (valuePtr->value)
valuePtr = tree2.getNextAfter (valuePtr)
Following that, tree1 will then be a merge of the two trees and you can do what you want with tree2.
Now that's the basic idea - you may want to handle things like duplicate removal or error conditions, but it should be a good enough start to get you going. There's often little point in using the internals of a data structure when the published interface gives you a cleaner way.
I'm trying to create a method which will add a char* to a LinkedList, ensuring that the linkedList is always sorted alphabetically. I have been given code to define a LinkedItem struct:
// Define our list item as 'struct ListItem', and also
// typedef it under the same name.
typedef struct ListItem {
char *s;
struct ListItem *p_next;
} ListItem;
I have also been given a method to add an item to the beginning of a list:
// Adds a new item to the beginning of a list, returning the new
// item (ie the head of the new list *)
ListItem* add_item(ListItem *p_head, char *s) {
// Allocate some memory for the size of our structure.
ListItem *p_new_item = malloc(sizeof(ListItem));
p_new_item->p_next = p_head; // We are the new tail.
p_new_item->s = s; // Set data pointer.
return p_new_item;
}
Now here's my code, I'll explain more after:
ListItem* addSortedItem(ListItem *p_head, char *s){
if(p_head==NULL)//if the list is empty, we add to the beginning
return add_item(p_head,s);
ListItem* p_new_item = malloc(sizeof(ListItem));
ListItem *p_current_item = p_head; //makes a pointer to the head of the list
while (p_current_item) { // Loop while the current pointer is not NULL
printf("entering while loop with current=%s\n",p_current_item->s);
// now we want to look at the value contained and compare it to the value input
if(aThenB(s,p_current_item->s)!=TRUE){
// if A goes after B, we want to go on to look at the next element
p_current_item=p_current_item->p_next;
} else if (aThenB(s,p_current_item->s)==TRUE) {printf("entered elseif\n");
p_head=add_item(p_current_item,s);
return p_head;
} else {printf("WHY DID WE EVER REACH THE ELSE!?"); return p_head;}
}
}
Now, aThenB(StringA,StringB) returns TRUE if the correct sorted order of A and B is A, then B, and false otherwise- equality is also an option, I simply haven't gotten this to work well enough to allow that :-)
What is happening with my test data (which is "sheep i", with i from 0-10) is that either I am only returning one element back, or i am randomly skipping elements, depending on the order input. I can include more code but it's a bit messy.
I think my problem is stemming from not fully understanding the pointers and how they work- I want to ensure that p_head is always pointing to the head, whilst p_current is roving through the list. But I'm also getting seg faults when p_current reaches the last element, so I'm not sure where I'm going wrong.
Thank you for any help on how to get my code to return properly :-)
Edit: addSortedItem() is called in the following block in the main method:
// The empty list is represented by a pointer to NULL.
ListItem *p_head = NULL;
ListItem *p_head2=NULL;
// Now add some items onto the beginning of the list.
int i;
for (i=0; i<NO_ITEMS; i++) {
// Allocate some memory for our string, and use snprintf to
// create a formatted string (see GNU API docs) much like printf
// but instead writing to memory rather than the screen.
char* s = malloc(MAX_DATA_CHARS);
snprintf(s, (size_t) MAX_DATA_CHARS, "sheep %d", i);
p_head = addSortedItem(p_head, s);
}
you have an error in the add of a new element in the middle or in the end of the linked list.
in your addStoredItem function you make a pointer from your newItem to the currentItem but you do not take account to have a link from previous element to the newItem
initial linked list befor calling addStoredItem
item1-->item2-->item4-->item5
Linked list afetr calling addStoredItem in order to add item3
item1-->item2-->item4-->item5
^
|
item3
so as you can see you have added the new item at the head of the sub linked list starting from item4 but you do not make link from item2 to item3
so that we have to keep a pointer to the previous item in order to complete the link.
the add_item() function allow to add item in the head
The same thing if you try to add item at the end of the linked list
item1-->item2-->item4-->item5 NULL
^
|
item6
the item6 has added as separate head and there is no link from item5 (previous) to item6 (new)
so your addStoredItem() function could be fixed like this
ListItem* addSortedItem(ListItem *p_head, char *s){
if(p_head==NULL)//if the list is empty, we add to the beginning
return add_item(p_head,s);
struct ListItem* p_new_item = malloc(sizeof(ListItem));
ListItem *p_current_item = p_head; //makes a pointer to the head of the list
ListItem *p_prev_item = NULL; //FIXED
while (p_current_item) { // Loop while the current pointer is not NULL
printf("entering while loop with current=%s\n",p_current_item->s);
// now we want to look at the value contained and compare it to the value input
if(aThenB(s,p_current_item->s)!=TRUE){
// if A goes after B, we want to go on to look at the next element
p_prev_item = p_current_item; //FIXED
p_current_item=p_current_item->p_next;
} else if (aThenB(s,p_current_item->s)==TRUE) {printf("entered elseif\n");
break;
} else {printf("WHY DID WE EVER REACH THE ELSE!?"); return p_head;}
}
if (p_prev_item!=NULL) //FIXED
p_prev_item->p_next=add_item(p_current_item,s); //FIXED
else //FIXED
p_head=add_item(p_current_item,s);//FIXED
return p_head; //FIXED
}
the fixed lines are indicated with //FIXED
At first, your p_head is NULL, so when you enter your addSortedItem function you create the list and add the first string. That's alright.
But then, upon adding the second item (which in your case is "sheep 1"), you enter your while (p_current_item) loop. The call to aThenB returns FALSE and you go to your next element which is.. NULL! Indeed, at this time, p_head looks like this:
p_head {
s = "sheep 0",
p_next = NULL
}
Your while condition is not true and you exit your function, nothing was added.
You could add a condition in your first if like:
if (p_current_item->next == NULL)
p_current_item->next = addSortedItem(NULL, s);
else
p_current_item = p_current_item->next;
Also, saying that p_head=add_item(p_current_item,s); is wrong. Suppose your list is something like:
"sheep 1" -> "sheep 2" -> "sheep 4" -> "sheep 5"
If you add "sheep 3", you will get this:
"sheep 1" -> "sheep 2" -> "sheep 3" -> "sheep 4" -> "sheep 5"
^
|
p_head
You won't be able to add "sheep 0" anymore. Don't return the return value of addSortedItem as the new p_head
Support stuff:
#define FALSE 0
#define TRUE 1
#define aThenB(a,b) (strcmp(a,b) <=0 ? TRUE : FALSE)
All the special cases can be avoided by modifying the function's signature to
accept a pointer to pointer.
void addSortedItem(ListItem **pp_head, char *s){
ListItem *p_new_item ;
for ( ;*pp_head; pp_head = &(*pp_head)->p_next) {
if (aThenB(s,(*pp_head)->s)==FALSE) break;
}
p_new_item = malloc(sizeof *p_new_item);
p_new_item->s = s;
p_new_item->p_next = *pp_head;
*pp_head = p_new_item;
}
The caller should do:
ListItem *root = NULL;
addSortedItem( &root, "sheep#0");
I have a stack which contains some integer data. I want to find out the min value from Stack in O(1) time. Any idea?
PS: There is no ordering (increasing/decreasing) of data in Stack.
Thanks,
Naveen
Use two stacks. One is the data, one is the minimums. When you push onto the data stack, push the new minimum onto the minimums stack (the new minimum is the min of the item you're pushing and whatever is currently on the top of the minimums stack), and when you pop, pop off of both stacks (so that the two stacks always have the same number of elements). To find the minimum element, just look at the top of the minimums stack.
Pushing, popping and finding the min value are O(1).
O(n) is the best you're gonna do - you'd have to check each one of the values and compare them to the aggregator minimum, otherwise how would you know you got the lowest?
If you want, you can store the minimum as the values are added, making the pushes more expensive for the benefit of an O(1) read (of the pre-calculated minimum), but that's it.
A stack by definition is push/pop (LIFO) data structure. You can't using a single stack!
I am not sure why you expect to do this in constant time for arbitrary length. The best you will be able to do is O(n)
You'll probably want some kind of priority heap if you want to always pop the least element. If you want to pop what was last pushed, but be able to know the order of the elements remaining in the stack, some kind of search tree e.g. red-black will support deletion of an element from an arbitrary position (your stack would have a pointer to the tree node so when you pop you can find it).
If you only need to know the minimum (or max) remaining in the stack then ESRogs' is optimal.
Here is the Python implementation of ESRogs algorithm using lists as stacks:
class ConstantStack:
def __init__(self):
self.stack = []
self.min_stack = []
def push(self,item):
self.stack.append(item)
if len(self.min_stack) == 0:
self.min_stack.append(item)
return
# Get the smaller item between the pushed item and the top of the stack
smallest = min(item,self.min_stack[-1])
self.min_stack.append(smallest)
def pop(self):
self.min_stack.pop()
return self.stack.pop()
def min(self):
# NOTE: min_stack[-1] is equivalent to peek()
return self.min_stack[-1]
Here is an example of its usage:
>>> s = ConstantStack()
>>> s.push(3)
>>> s.push(7)
>>> s.push(6)
>>> s.push(1)
>>> s.min()
1
>>> s.pop()
1
>>> # Now that 1 is gone, 3 is the next smallest
>>> s.min()
3
>>> s.pop()
6
>>> # 6 was popped but 3 still remains the smallest
>>> s.min()
3
>>> s.pop()
7
>>> s.min()
3
>>> s.pop()
3
#define STACKSIZE 50
typedef struct stack
{
int item[STACKSIZE];
int top;
}MULSTACKEX;
void InitStack(MULSTACKEX &st)
{
st.item[STACKSIZE] = 0;
st.top = -1;
}
void Push(MULSTACKEX &st1, MULSTACKEX &st2, int elem)
{
if(st1.top == -1)
{
st1.top++;
st1.item[st1.top] = elem;
st2.top++;
st2.item[st2.top] = elem;
}
else
{
st1.top++;
st1.item[st1.top] = elem;
if(elem < st2.item[st2.top])
{
st2.top++;
st2.item[st2.top] = elem;
}
}
}
void Display(MULSTACKEX &st1, MULSTACKEX &st2)
{
cout<<"stack1 elements: "<<endl;
for(int i = 0; i <= st1.top; i++)
{
cout<<st1.item[i]<<"->";
}
cout<<endl;
cout<<"stack2 elements: "<<endl;
for(int i = 0; i <= st2.top; i++)
{
cout<<st2.item[i]<<"->";
}
}
int Pop(MULSTACKEX &st1, MULSTACKEX &st2)
{
int elem = 0;
if(st1.item[st1.top] == st2.item[st2.top])
{
elem = st2.item[st2.top];
st2.top--;
elem = st1.item[st1.top];
st1.top--;
}
else
{
elem = st1.item[st1.top];
st1.top--;
}
return elem;
}
int FindMin(MULSTACKEX &st2)
{
int elem = st2.item[st2.top];
return elem;
}
int _tmain(int argc, _TCHAR* argv[])
{
MULSTACKEX stack1, stack2;
InitStack(stack1);
InitStack(stack2);
Push(stack1,stack2,13);
Push(stack1,stack2,17);
Push(stack1,stack2,5);
Display(stack1,stack2);
int min_elem1 = FindMin(stack2);
cout<<"Min element in the list is: "<<min_elem1<<endl<<endl;
int deletedelem2 = Pop(stack1,stack2);
cout<<"Pop element from the stack:"<< deletedelem2 <<endl<<endl;
Display(stack1,stack2);
cout<<endl<<endl;
Push(stack1,stack2,19);
Push(stack1,stack2,8);
Display(stack1,stack2);
cout<<endl<<endl;
int deletedelem1 = Pop(stack1,stack2);
cout<<"Pop element from the stack:"<< deletedelem1 <<endl<<endl;
Display(stack1,stack2);
int min_elem2 = FindMin(stack2);
cout<<"Min element in the list is: "<<min_elem2<<endl<<endl;
return 0;
}
Instead of pushing 1 value, we push a pair of numbers. first element will be element that you want to push, second element would be minimum element of the stack and we should keep track of the minimum element. (element,minOfStack)
let say you have an empty array. when first you push data to the stack,firs element is also minumum value.
data=[(1,1)]
then you add value 2. you check the minimim value of the stack which is 1, 1<2, so you push (2,1) to the array
data=[(1,1),(2,1)]
Here is the python implementation
class StackTrackingMin:
def __init__(self):
self._data=[]
def push(self,x:int)->None:
currentMin=self.getMin()
if currentMin==None or currentMin>x:
currentMin=x
self._data.append((x,currentMin))
def pop(self)->None:
self._data.pop() # pop does not return anything
def top(self)->int:
return self._date[-1] if self._data else None
def getMin(self)->int:
return self._data[-1][1] if self._data else None