Interview100-29 判断栈的push和pop序列

本文介绍了一种算法,用于判断给定的两个整数序列中,一个序列是否可能是另一个序列通过栈操作得到的弹出序列。通过新建栈及使用双指针策略,文章详细解释了如何验证这一可能性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

输入两个整数序列,其中一个序列表示栈的push顺序,判断另一个序列有没有可能是对应的pop序列。为了 简单起见,我们假设push序列的任意两个整数都是不相等的。

例如我们输入的push序列为:1,2,3,4,5,那么4,5,3,2,1就有可能是一个pop序列,但4,3,5,1,2就不可能是这个push序列得到的pop序列。

解法

  1. 新建一个栈对push序列的元素进行入栈出栈,使用poshi和popi两个指针分别指向push序列和pop序列中的元素。
  2. 将push序列中的元素依次进栈(同时移动pushi指针),直到和pop序列中的第一个元素相同。然后此时栈顶元素出栈,popi指向pop序列中的下一个元素。
  3. 如果此时栈顶元素与当前的popi指向的元素相同,则继续出栈顶元素,popi后移。
  4. 如果此时栈顶元素与popi指向的元素不同,并且如果push序列中的元素已经全部进栈,则返回false。如果此时push序列中的元素未全部进栈,则继续后移pushi指针并进栈,在于popi指向的元素进行比较。
  5. 如果最后,栈为空,pop序列也遍历完成,则返回true。
IS-POP-SERIES(int[] push, int[] pop, int n):
    if push.length != pop.length:
        return false;
    Stack<int> stack;
    int pushi = 0;
    int popi = 0;
    while popi < n:
        while stack.empty() or stack.top() != pop[popi]:
            if pushi < length:
                stack.push(push[pushi++]);
            else 
                return false;
        if !stack.empty() and stack.top() == pop[popi]:
            stack.pop();
            popi++;
    return true;

 

#include <iostream> #include <stdlib.h> using namespace std; void OPT_Agorithm(); void FIFO_Agorithm(); void LRU_Agorithm(); void LFU_Agorithm(); double Page_Loss_Rate(int, int); int Find_Exist(int*, int, int); int Find_LeastInteviewTime(int, int, int*, int); void Update_InHereTime(int*, int, int); int Find_LeastNotUseTime(int, int, int*); int Find_LeastNotInterviewTime(int, int*); void Print_Frame(int*, int); void Print_Menu(); int main() { int choice; do { Print_Menu(); cout << "请选择要实现的算法:"; cin >> choice; switch (choice) { case 1: OPT_Agorithm(); break; case 2: FIFO_Agorithm(); break; case 3: LRU_Agorithm(); break; case 4: LFU_Agorithm(); break; case 0: break; } system("pause"); system("cls"); } while (choice); return 0; } /* * 用于遍历 save_Frame[] 的 n 个存储页框, 是否有 “待定地址 -> addr” * 如果有就返回 ture, 否则返回 false */ int Find_Exist(int* save_Frame, int n, int addr) { for (int i = 0; i < n; i++) { if (save_Frame[i] == addr) { return i; } } return -1; } void Print_Menu() { /* 输入模块 */ cout << "+---------------------------------------+" << endl; cout << "|\t***算法清单***\t\t\t|" << endl; cout << "|\t1.最佳置换算法(OPT)\t\t|" << endl << "|\t2.先进先出算法(FIFO)\t\t|" << endl; cout << "|\t3.最近最久未使用算法(LRU)\t|" << endl << "|\t4.最不经常使用算法(LFU)\t\t|" << endl; cout << "|\t0.退出\t\t\t\t|" << endl; cout << "+---------------------------------------+" << endl; } void Print_Frame(int* save_Frame, int n) { cout << "\t"; for (int i = 0; i < n; i++) { if (i == 0) { if (save_Frame[i] == -999) cout << "/ /"; else cout << "/" << save_Frame[i] << "/"; } else { if (save_Frame[i] == -999) cout << " /"; else cout << save_Frame[i] << "/"; } } cout << endl; } void Init(int* n, int* len, int*& save_Frame, int*& interview_Array) { cout << "请输入 n :"; cin >> *n; save_Frame = new int[*n]; for (int i = 0; i < *n; i++) save_Frame[i] = -999; cout << "请输入地址走向的长度:"; cin >> *len; cout << "请输入地址走向:"; interview_Array = new int[*len]; for (int i = 0; i < *len; i++) cin >> interview_Array[i]; } /* * 缺页中断率: * 假设进程 P 在运行中成功的内存访问次数为 s * 不成功的访问次数为 F,则缺页中断率为 R = F/(S+F) */ double Page_Loss_Rate(int S, int F) { double ans = 1.0 * F / (1.0 * S + 1.0 * F) * 100; return ans; } int Find_LeastInteviewTime(int sta, int addr, int* interview_Array, int len) { for (int i = sta; i < len; i++) { if (interview_Array[i] == addr) { return i - sta; } } return 99999; } /* * 最佳置换算法(OPT): * 将以后永不使用的或许是在最长(未来)时间内不再被访问的页面换出。 * 第一行输入参数:n ,代表存储页框数 * 第二行输入参数:a_1、a_2、...、a_n,代表访问地址的走向 * 输出要求:输出内存驻留的页面集合,缺页次数以及缺页率; * 数据结构:数组 */ void OPT_Agorithm() { cout << "欢迎使用 OPT " << endl; int n, len, * save_Frame = NULL, * interview_Array = NULL; Init(&n, &len, save_Frame, interview_Array); //测试样例: 1 3 12 2 3 2 1 5 2 4 5 3 2 5 2 int addr; int cnt = 0; int score = 0; int fail_time = 0; int iter = 0; while (iter < len) { addr = interview_Array[iter]; iter++; cout << endl << "第" << iter << "轮:"; if (cnt < n) { if (Find_Exist(save_Frame, cnt, addr) != -1) { score++; cout << "\"" << addr << "\" 被命中了\t\t------->"; Print_Frame(save_Frame, n); } else // 未命中,但有空间," << "\" << addr << "\" 被装入 { fail_time++; cout << "未命中," << "\"" << addr << "\" 被装入 \t------->"; save_Frame[cnt] = addr; Print_Frame(save_Frame, n); cnt++; } } else { if (Find_Exist(save_Frame, n, addr) != -1) { score++; cout << "\"" << addr << "\" 被命中了\t\t------->"; Print_Frame(save_Frame, n); } else // 未命中,但没了空间 { fail_time++; int* least_Time = new int[n]; int max_Time = 0; int index; for (int i = 0; i < n; i++) { least_Time[i] = Find_LeastInteviewTime(iter, save_Frame[i], interview_Array, len); if (least_Time[i] > max_Time) { max_Time = least_Time[i]; index = i; } } cout << "\"" << addr << "\" 替换了 \"" << save_Frame[index] << "\"\t\t------->"; save_Frame[index] = addr; Print_Frame(save_Frame, n); delete[] least_Time; } } } cout << endl; cout << "缺页次数为:" << fail_time << endl; cout << "缺页中断率 R = " << Page_Loss_Rate(score, fail_time) << "%" << endl; delete[] save_Frame; delete[] interview_Array; } void Update_InHereTime(int* in_HereTime, int n, int ind) { for (int i = 0; i < n; i++) { in_HereTime[i]++; } if (ind != -1) in_HereTime[ind] = 0; } /* * 先进先出算法(FIFO): * 淘汰最先使用内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。 * 数据结构:数组 * 第一行输入参数:n ,代表存储页框数 * 第二行输入参数:a_1、a_2、...、a_n,代表访问地址的走向 * 输出要求:输出内存驻留的页面集合,缺页次数以及缺页率; */ void FIFO_Agorithm() { int n, len, * save_Frame = NULL, * interview_Array = NULL; Init(&n, &len, save_Frame, interview_Array); int* in_HereTime = new int[n]; for (int i = 0; i < n; i++) in_HereTime[i] = 0; // 初始化都为零 //测试样例: 2 3 12 2 3 2 1 5 2 4 5 3 2 5 2 int addr; int cnt = 0; int score = 0; int fail_time = 0; int iter = 0; while (iter < len) { cout << endl << "第" << iter << "轮:"; addr = interview_Array[iter]; iter++; if (cnt < n) { if (Find_Exist(save_Frame, cnt, addr) != -1) { score++; cout << "\"" << addr << "\" 被命中了\t\t------->"; Print_Frame(save_Frame, n); Update_InHereTime(in_HereTime, cnt, -1); } else // 未命中,但有空间 { fail_time++; cout << "未命中," << "\"" << addr << "\" 被装入 \t------->"; save_Frame[cnt] = addr; Print_Frame(save_Frame, n); Update_InHereTime(in_HereTime, cnt, cnt); cnt++; } } else { if (Find_Exist(save_Frame, n, addr) != -1) { score++; cout << "\"" << addr << "\" 被命中了\t\t------->"; Print_Frame(save_Frame, n); Update_InHereTime(in_HereTime, n, -1); } else // 未命中,但没了空间 { fail_time++; int max_Time = 0; int index; for (int i = 0; i < n; i++) { if (in_HereTime[i] > max_Time) { max_Time = in_HereTime[i]; index = i; } } cout << "\"" << addr << "\" 替换了 \"" << save_Frame[index] << "\"\t\t------->"; save_Frame[index] = addr; Print_Frame(save_Frame, n); int ind = Find_Exist(save_Frame, n, addr); Update_InHereTime(in_HereTime, n, ind); } } } cout << endl; cout << "缺页次数为:" << fail_time << endl; cout << "缺页中断率 R = " << Page_Loss_Rate(score, fail_time) << "%" << endl; delete[] save_Frame; delete[] interview_Array; delete[] in_HereTime; return; } int Find_LeastNotUseTime(int end, int addr, int* interview_Array) { for (int i = end - 1; i >= 0; i--) { if (interview_Array[i] == addr) { // cout << " i = " << i << endl; return end - i; } } return 99999; } /* * 最近最久未使用算法(LRU): * 淘汰最近最久未被使用的页面。 * 数据结构:数组 * 第一行输入参数:n ,代表存储页框数 * 第二行输入参数:a_1、a_2、...、a_n,代表访问地址的走向 * 输出要求:输出内存驻留的页面集合,缺页次数以及缺页率; */ void LRU_Agorithm() { int n, len, * save_Frame = NULL, * interview_Array = NULL; Init(&n, &len, save_Frame, interview_Array); //测试样例: 3 3 12 2 3 2 1 5 2 4 5 3 2 5 2 int addr; int cnt = 0; int score = 0; int fail_time = 0; int iter = 0; while (iter < len) { addr = interview_Array[iter]; iter++; cout << endl << "第" << iter << "轮:"; if (cnt < n) { if (Find_Exist(save_Frame, cnt, addr) != -1) { score++; cout << "\"" << addr << "\" 被命中了\t\t------->"; Print_Frame(save_Frame, n); } else // 未命中,但有空间 { fail_time++; cout << "未命中," << "\"" << addr << "\" 被装入 \t------->"; save_Frame[cnt] = addr; Print_Frame(save_Frame, n); cnt++; } } else { if (Find_Exist(save_Frame, n, addr) != -1) { score++; cout << "\"" << addr << "\" 被命中了\t\t------->"; Print_Frame(save_Frame, n); } else // 未命中,但没了空间 { fail_time++; int* Not_UseTime = new int[n]; int max_Time = 0; int index; for (int i = 0; i < n; i++) { Not_UseTime[i] = Find_LeastNotUseTime(iter, save_Frame[i], interview_Array); if (Not_UseTime[i] > max_Time) { max_Time = Not_UseTime[i]; index = i; } } cout << "\"" << addr << "\" 替换了 \"" << save_Frame[index] << "\"\t\t------->"; save_Frame[index] = addr; Print_Frame(save_Frame, n); delete[] Not_UseTime; } } } cout << endl; cout << "缺页次数为:" << fail_time << endl; cout << "缺页中断率 R = " << Page_Loss_Rate(score, fail_time) << "%" << endl; delete[] save_Frame; delete[] interview_Array; } int Find_LeastNotInterviewTime(int n, int* interview_Time) { int min_Time = 99999; int ind; for (int i = 0; i < n; i++) { if (interview_Time[i] < min_Time) { min_Time = interview_Time[i]; ind = i; } } return ind; } /* * 最不经常使用算法(LFU): * 即选择最近一段时间内最长时间没有被访问过的页面进行置换 * 数据结构:数组 * 第一行输入参数:n ,代表存储页框数 * 第二行输入参数:a_1、a_2、...、a_n,代表访问地址的走向 * 输出要求:输出内存驻留的页面集合,缺页次数以及缺页率; */ void LFU_Agorithm() { int n, len, * save_Frame = NULL, * interview_Array = NULL; Init(&n, &len, save_Frame, interview_Array); int* interview_Time = new int[n]; for (int i = 0; i < n; i++) interview_Time[i] = 0; // 测试样例一:4 3 12 2 3 2 1 5 2 4 5 3 2 5 2 // 测试样例二:4 3 12 2 3 2 1 2 1 5 4 2 4 4 6 int addr; int cnt = 0; int score = 0; int fail_time = 0; int iter = 0; while (iter < len) { cout << endl << "第" << iter << "轮:"; addr = interview_Array[iter]; iter++; if (cnt < n) { if (Find_Exist(save_Frame, cnt, addr) != -1) { score++; cout << "\"" << addr << "\" 被命中了\t\t------->"; Print_Frame(save_Frame, n); int ind = Find_Exist(save_Frame, cnt, addr); interview_Time[ind]++; } else // 未命中,但有空间 { fail_time++; cout << "未命中," << "\"" << addr << "\" 被装入 \t------->"; save_Frame[cnt] = addr; Print_Frame(save_Frame, n); cnt++; } } else { if (Find_Exist(save_Frame, n, addr) != -1) { score++; cout << "\"" << addr << "\" 被命中了\t\t------->"; Print_Frame(save_Frame, n); int ind = Find_Exist(save_Frame, n, addr); interview_Time[ind]++; } else // 未命中,但没了空间 { fail_time++; int index = Find_LeastNotInterviewTime(n, interview_Time); cout << "\"" << addr << "\" 替换了 \"" << save_Frame[index] << "\"\t\t------->"; save_Frame[index] = addr; interview_Time[index] = 0; Print_Frame(save_Frame, n); } } } cout << endl; cout << "缺页次数为:" << fail_time << endl; cout << "缺页中断率 R = " << Page_Loss_Rate(score, fail_time) << "%" << endl; delete[] save_Frame; delete[] interview_Array; delete[] interview_Time; }
最新发布
05-13
<think>好的,用户需要关于页面置换算法(OPT、FIFO、LRU、LFU)的C++实现代码,并且希望理解虚拟存储器的概念实现方法。首先,我需要确认用户的需求是否明确。他们可能是在学习操作系统,或者在做相关项目,需要具体的代码示例概念解释。 用户提到了四个算法:OPT、FIFO、LRU、LFU。我需要逐个分析每个算法的实现方法,并考虑如何用C++编写。同时,虚拟存储器的概念需要简明扼要地解释,可能涉及分页、页面置换的原因等。 接下来,代码示例部分要注意正确性可读性。比如,FIFO可以用队列实现,LRU可能需要链表或哈希表来跟踪最近使用情况,LFU则需要记录频率。OPT比较难,因为需要未来访问的信息,这在实际情况中不可行,但模拟时可能需要预先知道页面访问序列。 然后,虚拟存储器的实现方法部分需要联系页面置换算法的作用,说明它们如何帮助管理物理内存虚拟内存的关系,减少缺页中断,提升系统性能。 用户提供的引用中提到了工作集算法页面置换的分类,可能需要在解释时适当引用,但要注意用户真正的需求是代码概念,所以重点应放在实现原理上,而不是过多扩展其他算法。 最后,生成相关问题时要围绕页面置换算法的比较、应用场景、优缺点,以及虚拟存储器的其他方面,帮助用户深化理解。需要确保问题有针对性,能够引导用户进一步学习或解决实际问题。</think>### 页面置换算法C++实现与虚拟存储器解析 #### 一、虚拟存储器概念 虚拟存储器通过分页/分段技术扩展物理内存容量,允许进程拥有比实际内存更大的逻辑地址空间。当物理内存不足时,操作系统使用页面置换算法将部分页面换出到磁盘,需要时再换入[^1]。 核心特征: 1. 透明性:应用程序无需感知物理内存限制 2. 局部性原理:90%时间访问10%的数据(时间局部性+空间局部性) 3. 缺页中断处理流程: $$ \text{访问页表} \rightarrow \text{页缺失异常} \rightarrow \text{选择置换页} \rightarrow \text{写回磁盘} \rightarrow \text{装入新页} $$ #### 二、页面置换算法实现 ```cpp #include <iostream> #include <vector> #include <unordered_map> #include <queue> #include <list> #include <climits> using namespace std; // FIFO算法实现 int FIFO(vector<int> pages, int frameSize) { queue<int> q; unordered_set<int> s; int faults = 0; for (int page : pages) { if (s.size() < frameSize) { if (s.find(page) == s.end()) { s.insert(page); q.push(page); faults++; } } else { if (s.find(page) == s.end()) { int val = q.front(); q.pop(); s.erase(val); s.insert(page); q.push(page); faults++; } } } return faults; } // LRU算法实现 int LRU(vector<int> pages, int frameSize) { list<int> lru_list; unordered_map<int, list<int>::iterator> map; int faults = 0; for (auto page : pages) { if (map.find(page) != map.end()) { lru_list.erase(map[page]); } else { if (lru_list.size() == frameSize) { int last = lru_list.back(); lru_list.pop_back(); map.erase(last); faults++; } } lru_list.push_front(page); map[page] = lru_list.begin(); } return faults; } // OPT算法实现 int OPT(vector<int> pages, int frameSize) { unordered_set<int> s; unordered_map<int, int> next_use; int faults = 0; for (int i=0; i<pages.size(); i++) { int page = pages[i]; if (s.find(page) == s.end()) { if (s.size() < frameSize) { s.insert(page); } else { int farthest = -1, val; for (auto p : s) { int j; for (j=i+1; j<pages.size(); j++) { if (pages[j] == p) break; } if (j > farthest) { farthest = j; val = p; } } s.erase(val); s.insert(page); } faults++; } } return faults; } // LFU算法实现 int LFU(vector<int> pages, int frameSize) { unordered_map<int, int> freq; unordered_map<int, list<int>::iterator> iter_map; unordered_map<int, list<int>> freq_map; int min_freq = 0, faults = 0; for (auto page : pages) { if (iter_map.find(page) != iter_map.end()) { int cur_freq = freq[page]; freq_map[cur_freq].erase(iter_map[page]); freq[page]++; freq_map[cur_freq+1].push_front(page); iter_map[page] = freq_map[cur_freq+1].begin(); if (freq_map[min_freq].empty()) min_freq++; } else { if (iter_map.size() == frameSize) { int evict = freq_map[min_freq].back(); freq_map[min_freq].pop_back(); iter_map.erase(evict); freq.erase(evict); } freq[page] = 1; freq_map[1].push_front(page); iter_map[page] = freq_map[1].begin(); min_freq = 1; faults++; } } return faults; } ``` #### 三、算法特性对比 | 算法 | 时间复杂度 | Belady异常 | 实现复杂度 | 适用场景 | |------|------------|------------|------------|----------| | FIFO | $O(1)$ | 会发生 | 简单 | 低内存系统 | | LRU | $O(1)$ | 不会 | 中等 | 通用系统 | | OPT | $O(n^2)$ | 不会 | 理论模型 | 性能基准 | | LFU | $O(1)$ | 可能发生 | 复杂 | 长期访问模式统计 | #### 四、虚拟存储器实现要点 1. 页表结构:采用多级页表减少内存占用 2. TLB加速:通过$Translation\ Lookaside\ Buffer$缓存常用页表项 3. 工作集模型:根据$W(t, Δ) = \{ pages\ accessed\ in\ (t-Δ, t) \}$确定活跃页面[^2] 4. 写策略选择: - 写回法(Copy-on-Write) - 写直达法(Write-Through)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值