More Related Content
Similar to Lecture 5 (20)
Lecture 5
- 2. Стек
• Стек нь өгөдөл хийх ба гаргаж авах гэсэн 2 үйлдэл бүхий шугаман
бүтэц бөгөөд эдгээр үйлдлүүдийг стекийн орой гэх зөвхөн нэг
төгсгөлд гүйцэтгэдэг. Өөрөөр хэлбэл стекийн орой дахь хамгийн
сүүлд орсон элемент нь хамгийн түрүүнд гарах зарчмаар
ажилладаг. Иймээс стекийг сүүлд орсон нь эхэлж гарах (LIFO-last
in first out) жагсаалт гэж бас нэрлэдэг. Стек нь рекурсив
програмчлалын үндэс юм. Бидний хэрэглэж буй компьютер бүр
стектэй байдаг. Өөрөөр хэлбэл дахин шинэ стек хийх шаардлага
үүсдэггүй
• Ассемблер хэлээр push, pop командыг бичихэд стекэд өгөгдөл
нэмж, хасах боломжтой.
- 3. Стекийн шаардлага
Хэдийгээр стек нь маш хязгаарлагдмал үйлдэлтэй боловч
компьютерийн програмчлалд чухал үүрэгтэй өгөгдлийн бүтцүүдийн
нэг юм. Тухайлбал ямар нэг ажлын явцад өөр зүйл хийхээр түр
хойшлуулах, эсвэл програм бүхэлдээ ийм зарчмаар ажиллах зэрэг
олон алгоритмд стек үндсэн үүрэг гүйцэтгэнэ. Жишээ нь CALL,
RETURN зэрэг функцэд стекийг ашигладаг байна.
- 4. Стекийг массив ашиглан нэвтрүүлэх
• Стекийг олон янзын аргаар нэвтрүүлж болох боловч ихэвчлэн
шугаман массив, эсвэл нэг холбоост жагсаалт ашигладаг. Массив
ашиглах стекийг ихэвчлэн гараар тодорхойлж өгдөг. Дараах Stack
классын зарлалтаар MaxSize хэмжээтэй stack массив, стекийн
оройг тодорхойлох top хувьсагч болон стекд элемент хийх push(),
стекээс элемент авах pop() функц бусад туслах функцүүдийн хамт
тодорхойллоо. Stack массивыг заагчаар тодорхойлсноор динамик
ойгоос new операторын тусламжтайгаар MaxSize хэмжээтэй зайг
Stack классын обьект зарлах үед нөөцлөн авна. Энэ нь хэдийгээр
заагч ашиглаж байгаа боловч хувиарлалт хийснээс хойш түүний
хэмжээ MaxSize-аас хэтрэхгүй тул статикаар тодорхойлогдож
байна.
- 5. class Stack{
int top, MaxSize;
Type *stack;
public:
Stack(int Msize) : MaxSize(Msize)
(stack new Type(MazSize); top=1;)
Stack()
{delete() stack;}
bool push(const Type item);
bool pop(Type & item);
bool empty();
bool fill();
}
Ингэж Stack классыг загвар класс байдлаар тодорхойлсон тохиолдолд дурын
өгөгдлийн төрөлд ажиллах обьектуудыг нэг програмд үүсгэн ажиллаж болно.
- 6. Стекийг жагсаалтаар илэрхийлэх
• Стекийг массиваар илэрхийлэх үед стекийн хэмжээ нь тогтмол
тодорхойлогдох учир өөрчлөх боломжгүй юм. Хэрэв програм
зохиогч нь стекд хадгалагдах нийт өгөгдлийн хэмжээг итгэлтэй
мэдэж байвал стекийг массив ашиглан нэвтрүүлэх нь зохимжтой.
Гэвч зарим бодлогын хувьд стекд хадгалагдах өгөгдлийн хэмжээг
урьдчилан хэлэх боломжгүй тохиолдлууд байдаг. Энэ тохиолдолд
стекийг нэг хэмжээст жагсаалтаар илэрхийлнэ. Стекийг
жагсаалтаар илэрхийлснээр түүний хэмжээ нь бодлогын нөхцлөөс
хамаарч програм ажиллах явцад динамикаар өөрчлөгдөх
боломжтой.
- 7. class Stack{
struct Node
{
Type data; Node *link;
};
Node *top;
public:
Stack() {top=NULL;}
~Stack(){
Node *temp;
while (top){
temp=top; top=top->link;
delete temp;
}
}
bool push(const Type item);
bool pop(Type & item);
bool empty();
}
• Дээрхи зарлалтаар стекийн нэг элемент нь
өгөгдөл ба холбоос гэсэн 2 хэсгээс тогтох
жагсаалтын адил тодорхойлогдсон байна. top
заагч нь жагсаалтын эхлэл буюу стекийн оройг
заах ба NULL утгатай байх үед стек үүсгэх
ба ~Stack() байгуулагч функц нь хоосон стек
үүсгэх ба -Stack() устгагч функц нь стекийг
санах ойгоос чөлөөлнө. Стект элемент хийх
push() болон элемент авах pop() функцүүд нь
top заагчийн тусламжтайгаар стекийн оройд
үйлдлийг гүйцэтгэнэ.
- 8. Стекийн хэрэглээ
Стекийн хэрэглээг дараах хэдэн жишээгээр иш татан тайлбарлая.
Эхний жишээнд 10-тын тооллын системд өгөгдсөн бүхэл тоог хоёртын тоололд шилжүүлэх бодлогыг стек ашиглан бичвэл:
void main()
{
Stack <int> binary;
char ch;
int n;
do{
cout<<"n=";
cin>>n;
while(n){
binary.push(n%2);
n/=2;
}
while(!binary.empty()){
binary.pop(n);
cout<<n;
}
cout<<"nMore (Y or N)?:";
cin>>ch;
} while (ch=='Y'||ch=='y')
}
- 9. • Дээрх програмд binary стекийг Stack загвар классын бүхэл тоо
хадгалах обьектоор зарласан. Энэ бодлогын хувьд жагсаалтаар
нэвтрүүлсэн Stack классыг ашиглах нь тохиромжтой. Учир нь
тооны утгаас хамаарч хоёртын тоололд гарах тооны оронгийн тоо
(урт) өөр өөр байх тул стекд орох нийт элементийн тоог
урьдчилан хэлэх аргагүй.
- 10. Хаалтын баланс шалгах алгоритм
• Стек ашиглан энэ асуудлыг шийдвэрлэх нь хамгийн тохиромжтой.
Тэмдэгтүүдийн цувааны эхнээс тэмдэг бүрийг уншин, нээх хаалт
тааралдах бүрд түнийг стекд хийх ба хаах хаалт таарвал стекээс
нэг элемент авч харгалзах нээх хаалт байгаа эсэхийг шалган, зөв
тохиолдол цааш үргэлжлүүлэн шалгана. Өөрөөр хэлбэл нээх
хаалтнууд стекд орсон дарааллын эсрэг дарааллаар харгалзан
хаах хаалтууд байх ёстой.
- 11. Арифметик илэрхийлэл
• Арифметикийн илэрхийлэл бодоход үйлдлийн тэмдэгүүдийн
гүйцэтгэх дараарллыг баримтлах ёстой. Өөрөөр хэлбэл эхлээд
хаалтан дахь үйлдлийг, дараа нь зэрэг дэвшүүлэх үйлдлийг, дараа
нь үржих ба хуваах, эцэст нь нэмэх ба хасах гэсэн дарааллаар
гүйцэтгэдэг.
• Жишээ нь: 3*(2+1)*2-8/(9-5)=2*9-8/4=16