實驗題目:簡單行編輯程序
一,題目:
30、簡單行編輯程序
[問題描述]
文本編輯程序是利用計算機進行文字加工的基本軟件工具,實現對文本文件的插入、刪除等修改操做。限制這些操做以行爲單位進行的編輯程序稱爲行編輯程序。
被編輯的文本文件可能很大,所有讀入編輯程序的數據空間(內存)的作法既不經濟,
也不總能實現。一種解決方法是逐段地編輯。任什麼時候刻只把待編輯文件的一段放在內存,稱爲活區。試按照這種方法實現一個簡單的行編輯程序。設文件每行不超過 320 個字符,不多超過 80 字符。
[基本要求]
實現如下 4 條基本編輯命令:
(1) 行插入。格式:i<行號><回車><文本><回車>
將<文本>插入活區中第<行號>行以後
(2)行刪除。格式:d<行號 1>[□<行號 2>]<回車>
刪除活區中第<行號 1>行(到第<行號 2>行)。兩種格式的例子是:「d10↙」和「d10□14↙」
(3)活區切換。格式:n<回車>
將活區寫入輸出文件,並從輸入文件中讀入下一段,做爲新的活區。
(4)活區顯示。格式:p<回車>
逐頁地(每頁 20 行)顯示活區內容,每顯示一頁以後請用戶決定是否繼續顯示之後各
頁(若是存在)。印出的每一行要前置以行號和一個空格符,行號固定佔 4 位,增量爲 1。
各條命令中的行號均須在活區中各行行號範圍以內,只有插入命令的行號能夠等於活區
第一行行號減 1,表示插入當前屏幕中第一行以前,不然命令參數非法。
13 [選做內容] (1) 對於命令格式非法等一切錯誤做嚴格檢查和適當處理。 (2) 加入更復雜的編輯操做,如對某行進行串替換;在活區內進行模式匹配
2、要解決的問題
(1) 行插入。
(2)行刪除。
(3)活區切換。
(4)活區顯示。
附加:
(5)在活區內進行多或單模式匹配
3、算法基本思想描述:
對於題目的要求,在進行活區切換及顯示,行插入,行刪除,模式匹配都要求涉及鏈表,因此對鏈表進行的基本操做在課設中有所體現,而在附加功能中,使用了AC自動機,進行匹配,來提升時間效率。
AC自動機,其實相似於字典樹+KMP算法,經過構建匹配失敗後的fail指針,來構建AC自動機的模式匹配樹,而fail的構建涉及bfs算法,而fail的構建算法,首先先將鏈接於root的點的全部子節點連向root的點,再將全部非NULL的點壓入隊列,彈出進行操做,考慮節點失配的狀況,讓失配的節點p->next[i]->fail=p->fail->next[i];這個過程後就能夠創建一顆帶fail節點的字典樹。
而在自動機的匹配過程當中就是按照生成的fail樹對應匹配。即匹配失敗就移動到p->next[i]->fail.
順帶補充下字典樹的創建,
本課設的字典樹是採用指針版,即一個節點下有對應的30的子指針,表明a-z,而後若是爲空即表明沒有這個字母。若是不爲空,這表明有這個字母,假設abc,fde創建的字典樹如圖:node
4、設計
1. 數據結構的設計
(1)儲存結構:
1.
const int MAXN = 81;
const int MAXNS = 1024;
char file_name[MAXNS]; ///儲存用戶輸入的地址
char file_ends_name[MAXNS]; ///儲存文本輸出的地址
char AC_TIRE_ARR[325 * 25];///表明AC自動機要匹配的數組
2.讀出和讀入文件的數據結構:
typedef struct NODE
{
char words[MAXN];///表明每一個節點中儲存的數據
struct NODE *next;///指向下一個節點
int num; ///表明行數(供輸出的時候使用)
bool flag; ///flag表明行結束,行沒結束時,flag==false,結束時///將其標記爲true
} node;
3.AC自動機中的字典樹的數據結構
typedef struct TIRE
{
struct TIRE *next[30];///表明指向字典樹子節點
bool flag;///表明匹配串是否結束了
struct TIRE *fail;///指向失配後的位置
} tire;ios
2.算法的設計
2.1函數的思路詳解
(1)向系統申請node類型的空間,並返回給node型指針
node *creat()
(2)判斷讀取的數據是否爲文件尾的數據
bool PD1(char word[]) ///判斷行是否結束
其主要思路經過對數組word的strlen(word)-1來進行判斷,由於txt文檔中的數據讀取一行的話,行末會帶’\n’,因此’\n’能夠表明一行的結束
(3)從文件中讀取到鏈表中來構建數據。
int get_hang(char fileopenname[MAXNS], node *head, int move, int &fflag)
使用fgets函數從文件中讀取一行中的81個字符到儲存數據的鏈表中,而後在讀取到一行結束的時候把node結構體中的flag=true,來標記結束。
(4)輸出從文件中讀取到鏈表的內容
void PRINTNODE(node *head) ///輸出鏈表
經過head來讀取數據,若是遇到flag==true的就證實,該行到達告終束,輸出換行,接着輸出該節點的序號,而後循環。
(5),清空函數
void clearl(node *p)///釋放鏈表,防止內存泄露
void clear()///清屏函數
(6)///菜單生成表
void view()
(7)針對於添加後超出活區限制,提交到文件中
void only_insert(char strs[305], node *&head)///把第一行輸出到文本中
由於題意中代表了,會出現添加超過了活區的狀況,那麼我就將活區鏈表的第一個節點提交到文件中,而且將第一個節點經行移動。而後從新創建序號。
(8)把修改後的活區讀入文件中
void INPUT_file(char file_sname[MAXNS], node *head)
經過申請一箇中轉數組來儲存第一行的數據,經過對鏈表的讀取來儲存數據,而後經過fput讀入文件。
(9),表明刪除一個行區間
其原理爲算法
void del_file_one(int ans1, int ans2, node *&head) ///表明刪除一個區間
採用兩個指針來實現,一個指向要刪除的行的前一個的節點,一個指向後一個節點,採用將前一個指針指向後一個指針來實現區間刪除。
關於刪除第一個節點,直接將頭指針移動到下一個行節點。就能夠了。
多出來的節點能夠經過刪除函數進行刪除。數組
(10),刪除單行
void del_file_two(int ans1, node *&head)
原理也是採用兩個兩個節點來跑,一個指向要刪除的行的前一個的節點,一個指向後一個節點,採用將前一個指針指向後一個指針來實現單行刪除。
原理圖跟上述同樣
(11),建立AC自動機的字典樹部分的節點
tire *creat_tire()
申請一個節點,而且將其相連的子節點==NULL
而後把標記變成0;標記的意思是是否走到這個子匹配串的末尾。
(12),在字典樹中插入匹配子串
一個節點下有對應的30的子指針,表明a-z,而後若是爲空即表明沒有這個字母。若是不爲空,這表明有這個字母,假設abc,fde創建的字典樹如圖:數據結構
void insert_tire(char words[], tire *root)
思路就是對子串數組進行遍歷,若是第一個節點下的對應節點爲NULL的話就創建這個節點,而創建的方式有個核心,就是next【ans】,ans=words【i】-’a’;
來獲取,應用了ascii碼的運算
(13)生成fail指向
/**
經過構建匹配失敗後的fail指針,來構建AC自動機的模式匹配樹,而fail的構建涉及bfs算法,而fail的構建算法,首先先將鏈接於root的點的全部子節點連向root的點,再將全部非NULL的點壓入隊列,彈出進行操做,考慮節點失配的狀況,讓失配的節點p->next[i]->fail=p->fail->next[i];這個過程後就能夠創建一顆帶fail節點的字典樹。涉及bfs,即廣度優先搜索!
而在自動機的匹配過程當中就是按照生成的fail樹對應匹配。即匹配失敗就移動到p->next[i]->fail.函數
**/
void build_ACtire(tire *root)
(14)查找匹配的位置
如圖:工具
bool ACTIRE_search(char str[], tire *root)ui
將查找串與匹配串所創建的fail樹進行匹配,若是匹配失敗就訪問匹配失敗的fail指針再次經行匹配。匹配成功就返回匹配的的字段的位置。this
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cstdlib> #include <queue> #include <vector> using namespace std; const int MAXN = 81; const int MAXNS = 1024; char file_name[MAXNS]; ///用戶輸入的地址 char file_ends_name[MAXNS]; ///文本輸出的地址 char AC_TIRE_ARR[325 * 25]; typedef struct NODE { char words[MAXN]; struct NODE *next; int num; ///表明行數 bool flag; ///flag表明行結束 } node; typedef struct TIRE { struct TIRE *next[30]; bool flag; struct TIRE *fail; } tire; node *head; node *creat() { node *p; p = new node; memset(p->words, 0, sizeof(p->words)); p->num = 1; p->flag = false; p->next = NULL; return p; } bool PD1(char word[]) ///判斷行是否結束 { int len = strlen(word); if (word[len - 1] == '\n') { return true; } else return false; } int get_hang(char fileopenname[MAXNS], node *head, int move, int &fflag) ///fflag表明是否讀到文件尾 { FILE *fp; int re; ///表明字節數 int biaoji = 0; re = 0; fp = fopen(fileopenname, "r"); fseek(fp, move, 0); int number = 1; ///number表明行數 while (fgets(head->words, 81, fp) != NULL) { re += (strlen(head->words) + 1); //printf("%d\n",re); if (PD1(head->words)) { number++; if (number == 21) { fflag = 1; break; } head->flag = true; node *p; p = creat(); p->num = number; head->next = p; head = head->next; } else { node *p; p = creat(); p->num = number; head->next = p; head = head->next; } } fclose(fp); return re; } void PRINTNODE(node *head) ///輸出鏈表 { if (head == NULL) { printf("error,no thing\n"); return; } printf("%4d ", head->num); while (head) { printf("%s", head->words); if (head->flag == true) { //printf("...\n"); int lens = strlen(head->words); if (head->words[lens - 1] != '\n') printf("\n"); ///這個是針對於添加以後的。 if (head->next != NULL) printf("%4d ", head->next->num); } head = head->next; } //puts(""); } void clearl(node *p) { if (p != NULL) { clearl(p->next); free(p); } } void clear() { system("cls"); } void view() { printf("\n"); printf("活區切換。格式:n<回車>\n"); printf("活區顯示。格式:p<回車> \n"); printf("行插入。格式:i<行號><回車><文本><回車> \n"); printf("行刪除。格式:d<行號 1>[ <行號 2>]<回車> \n"); printf("活區多或單模式匹配。 格式:m<模式串 1>[ <模式串 2> ......]<回車>\n"); } void only_insert(char strs[305], node *&head) { node *hhead; hhead = head; int j = 0; char wordss[325]; int ans; while (hhead->flag == false) { ans = strlen(hhead->words); for (int i = 0; i < ans; i++) { wordss[j] = hhead->words[i]; j++; //printf("...........\n"); } } ans = strlen(hhead->words); for (int i = 0; i < ans; i++) { //printf("%c",hhead->words[i]); wordss[j] = hhead->words[i]; j++; } if (wordss[j - 1] != '\n') wordss[j] = '\n'; FILE *fp = fopen(strs, "a+"); fputs(wordss, fp); fclose(fp); hhead = hhead->next; head = hhead; } void add_hang(int n, node *&head) { int j = 0; node *p; node *begins; node *headss = creat(); node *heads = creat(); begins = creat(); p = creat(); heads = head; headss = head; begins = p; p->num = n + 1; char str[355]; printf("please the words \n"); cin >> str; getchar(); int len = strlen(str); for (int i = 0; i < len; i++) { p->words[j++] = str[i]; if (j == 81) { j = 0; node *q; q = creat(); q->num = n + 1; p->next = q; p = p->next; } } //p->words[j]='\n'; p->flag = true; if (n == 0) { p->next = head; head = p; headss = head; //printf("%s\n",head->words); int numbers = 1; while (headss) { headss->num = numbers; if (headss->flag == true && headss->next != NULL) { numbers++; } headss = headss->next; } //PRINTNODE(head); if (numbers > 20) { only_insert(file_ends_name, head); } node *hhead; hhead = creat(); hhead = head; numbers = 1; while (hhead) { hhead->num = numbers; if (hhead->flag == true) { numbers++; } hhead = hhead->next; } } else { while (headss->next->num != begins->num) { //printf("%d\n",headss->next->num); headss = headss->next; if (headss->next == NULL) { break; } } headss->flag = true; p->next = headss->next; headss->next = begins; int numbers = 1; while (heads) { heads->num = numbers; if (heads->flag == true && heads->next != NULL) { numbers++; } heads = heads->next; } //PRINTNODE(head); if (numbers > 20) { only_insert(file_ends_name, head); } node *headsss; headsss = creat(); headsss = head; numbers = 1; while (headsss) { headsss->num = numbers; if (headsss->flag == true) { numbers++; } headsss = headsss->next; } } } void INPUT_file(char file_sname[MAXNS], node *head) { char buf[MAXN * 10]; memset(buf, 0, sizeof(buf)); FILE *fps = fopen(file_sname, "a+"); int j = 0; while (head) { int len = strlen(head->words); for (int i = 0; i < len; i++) { buf[j] = head->words[i]; j++; } if (head->flag == true && head->next == NULL) { //printf("%s\n",buf); fputs(buf, fps); j = 0; memset(buf, 0, sizeof(buf)); } if (head->flag == false && head->next == NULL) { fputs(buf, fps); j = 0; memset(buf, 0, sizeof(buf)); } if (head->flag == true && head->next != NULL) { int lens = strlen(head->words); if (head->words[lens - 1] != '\n') buf[j] = '\n'; fputs(buf, fps); j = 0; memset(buf, 0, sizeof(buf)); } head = head->next; } fclose(fps); } void Node_clear(node *s, node *h) { while (s != h) { //printf("...........\n"); Node_clear(s->next, h); delete s; } } void del_file_one(int ans1, int ans2, node *&head) ///表明刪除一個區間 { node *head1; ///表明指向前一個的指針 head1 = creat(); node *head2; ///表明指向後一個的指針 head2 = creat(); node *head3; ///釋放內存空間 head3 = creat(); node *head4; head4 = creat(); head1 = head; head2 = head; ///ans1 ans2 0 10 表明0到10都被刪除 if (ans1 != 1) { while (head1->next->num != ans1) { head1 = head1->next; } while (head2->next->num != ans2 + 1) { head2 = head2->next; if (head2->next == NULL) { break; } } head3 = head1->next; head4 = head2; head1->next = head2->next; //Node_clear(head3,head2); /** 如下是一個從新構造輸出數據的函數 **/ node *heads; heads = creat(); heads = head; int numbers = 1; while (heads) { heads->num = numbers; if (heads->flag == true) { numbers++; } heads = heads->next; } } else if (ans1 == 1) { while (head2->next->num != ans2 + 1) { head2 = head2->next; if (head2->next == NULL) { break; } } //printf("%s\n",head2->words); head3 = head; head4 = head2; head2 = head2->next; head = head2; //Node_clear(head3,head4); node *headss; headss = creat(); headss = head; int numbers = 1; while (headss) { headss->num = numbers; if (headss->flag == true) { numbers++; } headss = headss->next; } } } void del_file_two(int ans1, node *&head) { if (ans1 == 1) { node *heads; heads = creat(); heads = head; while (heads->next->num == 1) { heads = heads->next; if (heads->next == NULL) { break; } } heads = heads->next; head = heads; node *head1; head1 = creat(); head1 = head; int numbers = 1; while (head1) { head1->num = numbers; if (head1->flag == true) { numbers++; } head1 = head1->next; } } else { int ans2 = ans1 + 1; node *head1; head1 = creat(); head1 = head; node *head2; head2 = creat(); head2 = head; while (head1->next->num != ans1) { head1 = head1->next; if (head1->next == NULL) break; } while (head2->next->num != ans2) { head2 = head2->next; if (head2->next == NULL) { break; } } head2 = head2->next; head1->next = head2; int nums = 1; node *head3; head3 = creat(); head3 = head; while (head3) { head3->num = nums; if (head3->flag == true) nums++; head3 = head3->next; } } } tire *creat_tire() { tire *p; p = new tire; p->flag = false; for (int i = 0; i < 30; i++) { p->next[i] = NULL; } p->fail = NULL; return p; } //tire *root = creat_tire(); void insert_tire(char words[], tire *root) { int len; len = strlen(words); tire *p; p = root; for (int i = 0; i < len; i++) { int ans; ans = words[i] - 'a'; //printf("%d\n",ans); if (p->next[ans] == NULL) { tire *q; q = creat_tire(); p->next[ans] = q; } p = p->next[ans]; } p->flag = true; ///表明結束 } void build_ACtire(tire *root) { tire *p = root; tire *q; queue<tire *> que; for (int i = 0; i < 30; i++) { if (p->next[i] != NULL) { p->next[i]->fail = root; que.push(p->next[i]); } else p->next[i] = root; } while (!que.empty()) { tire *to; to = que.front(); que.pop(); for (int i = 0; i < 30; i++) { ///由於第一個模式串若是匹配失敗,有多是另外一個匹配串 ///因此應該找到另外一個 ///失配的話,就是回到root點再尋找 if (to->next[i] != NULL) { to->next[i]->fail = to->fail->next[i]; que.push(to->next[i]); } else to->next[i] = to->fail->next[i]; } } } bool ACTIRE_search(char str[], tire *root) { vector<int> vec; int len = strlen(str); //printf("%d\n",len); tire *ans; ans = creat_tire(); ans = root; for (int i = 0; i < len; i++) { int num = str[i] - 'a'; if (num < 0) continue; //printf("%d...\n",num); if (ans->next[num] != NULL) { ans = ans->next[num]; //printf("%d....\n",ans->flag); if (ans->flag == true) { //if(ans==NULL) //printf("............................................\n"); vec.push_back(i); } } else { if (ans == root) i++; else { ans = ans->fail; if (ans->flag == true) { vec.push_back(i); } } } } if (vec.size() != 0) { for (int i = 0; i < vec.size(); i++) { printf("%d ", vec[i]); } puts(""); return true; } return false; } int main() { int file_move = 0; node *p; int end_flag = 0; printf("please cin the in file_name\n"); cin >> file_name; getchar(); printf("please cin the out file_name\n"); cin >> file_ends_name; getchar(); while (1) { view(); node *head; char s[100]; char strs[105]; int nums; gets(s); if (s[0] == 'n') { if (file_move == 0) { head = creat(); nums = get_hang(file_name, head, file_move, end_flag); if (nums == 0) { printf("error\n"); continue; } file_move += nums; PRINTNODE(head); } else { INPUT_file(file_ends_name, head); head = creat(); nums = get_hang(file_name, head, file_move, end_flag); if (nums == 0) { printf("the file open is error\n"); printf("because the file is end\n"); continue; } file_move += nums; PRINTNODE(head); } } if (s[0] == 'p') { PRINTNODE(head); } if (s[0] == 'i') { int ans = 0; int len; len = strlen(s); for (int i = 1; i < len; i++) { if (s[i] >= '0' && s[i] <= '9') { ans = ans * 10 + (s[i] - '0'); } else break; } add_hang(ans, head); } if (s[0] == 'd') { int ans1, ans2; ans1 = 0; ans2 = 0; int i; int len = strlen(s); for (i = 1; i < len; i++) { if (s[i] >= '0' && s[i] <= '9') { ans1 = ans1 * 10 + (s[i] - '0'); } else break; } if (i == len) { del_file_two(ans1, head); } else { for (i = i + 1; i < len; i++) { if (s[i] >= '0' && s[i] <= '9') { ans2 = ans2 * 10 + (s[i] - '0'); } else break; } del_file_one(ans1, ans2, head); } } if (s[0] == 'm') { tire *root = creat_tire(); root = new tire; root->flag = false; for (int i = 0; i < 30; i++) root->next[i] = NULL; root->fail = NULL; char hzb[MAXN * 2]; memset(hzb, 0, sizeof(hzb)); int hzblen = strlen(s); int hzbj = 0; for (int i = 1; i < hzblen; i++) { if (s[i] == ' ') { hzb[hzbj] = '\0'; //printf("%s\n", hzb); insert_tire(hzb, root); hzbj = 0; continue; } hzb[hzbj++] = s[i]; } hzb[hzbj] = '\0'; //printf("%s\n", hzb); insert_tire(hzb, root); build_ACtire(root); node *hzb_head; hzb_head = creat(); hzb_head = head; memset(AC_TIRE_ARR, 0, sizeof(AC_TIRE_ARR)); int hzbz = 0; while (hzb_head) { int hhzb = strlen(hzb_head->words); for (int i = 0; i < hhzb; i++) if (hzb_head->words[i] != '\n') AC_TIRE_ARR[hzbz++] = hzb_head->words[i]; hzb_head = hzb_head->next; } AC_TIRE_ARR[hzbz] = '\0'; bool hflag = ACTIRE_search(AC_TIRE_ARR, root); if (hflag == false) printf("sorry!this is nothing\n"); } } return 0; }