汇编语言编程

汇编语言编程,第1张

; 本程序在MASMPlus 12集成环境下通过编译,经过调试,运行正确。

Code Segment

Assume CS:Code,DS:Code

; -------------------------------------

; 功能:显示指定地址(Str_Addr)的字符串

; 入口:

; Str_Addr=字符串地址(要求在数据段)

; 用法: Output Str_Addr

; 用法举例:Output PromptStr

Output MACRO Str_Addr

lea dx,Str_Addr

mov ah,9

int 21h

EndM

; -------------------------------------

; 功能:输出一个字符

; 入口:dl=要显示的字符

Output_Chr proc Near

push ax

mov ah,02h

int 21h

pop ax

ret

Output_Chr endp

; -------------------------------------

; 功能:输出回车换行

Output_CTLF proc Near

push ax

push dx

mov ah,02h

mov dl,0dh

int 21h

mov dl,0ah

int 21h

pop dx

pop ax

ret

Output_CTLF endp

; -------------------------------------

; 功能:取光标位置

; 入口:无

; 出口:DH=行号,DL=列号

GetCursor Proc Near

PUSH AX

PUSH BX

PUSH CX

XOR BX,BX

MOV AH,3

INT 10H

MOV Cursor_Row,DH

MOV Cursor_Col,DL

POP CX

POP BX

POP AX

RET

Cursor_Row DB

Cursor_Col DB

GetCursor EndP

; -------------------------------------

; 功能:置光标位置

; 入口:Cursor_Row=行坐标; Cursor_Col: 列坐标)

SetCursor Proc Near

PUSH CX

PUSH BX

PUSH AX

MOV DH,Cursor_Row

MOV DL,Cursor_Col

XOR BX,BX

MOV AH,2

INT 10H

POP AX

POP BX

POP CX

RET

SetCursor EndP

; -------------------------------------

; 功能:键盘输入一个指定位数的十进制数字,将其转换成二进制数并保存在指定的内存单元。

; 由于限定最大数据类型为字,所以,数字位数最多:5,最大无符号数:65536

; 约定:直接回车,视为数字0

; 入口:@@Digits=数字位数;di=保存输入的数字首地址

; @@Type_Data=保存的数据类型,B=字节类型,W=字类型。

; 出口:转换后的二进制数保存在di所指的单元

Input_Digit Proc Near

CR equ 000DH

LF equ 000AH

KBBack equ 0008H

push dx

push cx

push bx

push di

lea di,@@Save_Tmp

push di

cld

mov cl,@@Digits

xor ch,ch

push cx

@@Input: call GetCursor ;取光标位置

mov ah,1 ;从键盘接受一个字符

int 21h

cmp al,CR ;若键入的是回车,已经键入的数字不足N位

jz @@ASC_Dec ;转去处理已经键入的数字

cmp al,KBBack

jz @@KB_Back ;若是回空键,重新输入

cmp al,'0'

jb @@KBBack ;若低于数字'0',重新输入

cmp al,'9'

ja @@KBBack ;若低于数字'9',重新输入

jmp @@Save_Dig

@@KB_Back: dec Cursor_Col

inc cx

dec di

@@KBBack: call SetCursor ;置光标位置

jmp @@Input

@@Save_Dig: and al,0fh ;转换成二进制数

stosb ;保存

loop @@Input ;接受下一个数字

@@ASC_Dec: mov ax,cx

pop cx

pop si

sub cx,ax ;实际输入的数字位数

xor bp,bp

xor dx,dx

xor ax,ax

jcxz @@Save_Ret ;若直接回车,没有输入任何数字,按输入'0'处理

dec cx ;实际输入的数字位数减1,准备把输入的这一串数字转换成二进制数

jcxz @@One_Digit ;若输入的数字只有一位,转去直接保存这个二进制数

mov bx,10

@@Mul_Ten: lodsb

cbw

add ax,bp

mul bx

mov bp,ax

loop @@Mul_Ten

@@One_Digit: lodsb

cbw

add ax,bp

@@Save_Ret: pop di

cmp @@Type_Data,'B' ;字节类型?

jz $+5

stosw

jmp $+3

stosb

pop bx

pop cx

pop dx

ret

@@Digits db ;十进制数字位数

@@Type_Data db 'B' ;保存的数据类型。B=字节类型,W=字类型

@@Save_Tmp db 16 dup()

Input_Digit EndP

; -------------------------------------

; 功能:统计90以上,80~89,70~79,60~69,60以下学生个数

; 入口参数:AX=分数

Statics_Score Proc Near

push di

push dx

push ax

mov dl,10 ;除数

div dl ; 除10

cmp al,5 ; >5,及格

ja $+4

mov al,5 ; <=5,不及格

sub al,5 ; 减5,分数段计数地址偏移量

cbw ;

push ax

pop di

inc Score_Tab[di] ; 计数

pop ax

pop dx

pop di

ret

Statics_Score EndP

; -------------------------------------

; 功能:把AX中的二进制无符号数转换成显式的十进制ASCII码,并送显示屏显示

; 入口:AX=二进制数

; 出口:在当前光标位置显示转换后的ASCII码数字

Dec_ASCII Proc Near

push dx

push bx

push di

mov bx,10

lea di,@@Temp_Save[6]

mov BYTE ptr [di],'$'

dec di

@@Divide: xor dx,dx

div bx

or dl,30h

mov [di],dl

dec di

test ax,0ffffh

jnz @@Divide

inc di

push di

pop dx

mov ah,9

int 21h

pop di

pop bx

pop dx

ret

@@Temp_Save db 7 dup()

Dec_ASCII EndP

; -------------------------------------

; 功能:把AL中的二进制无符号数作为小数转换成显式的十进制ASCII码,

; 并送显示屏显示,未考虑四舍五入

; 入口:AH=二进制数,BH=除数,CX=保留小数位数

; 出口:在当前光标位置显示转换后的ASCII码数字

Dec_Frac Proc Near

push ax

mov dl,''

call Output_Chr ;显示一个小数点

pop ax

mov bl,10 ;乘数

@@Dec_Frac: mov al,ah ;余数不为0,处理小数部分

mul bl ;余数乘10,继续做除法

div bh ;除以除数,取商数作为结果的一位小数

or al,30h

mov dl,al

call Output_Chr ;显示一位小数

loop @@Dec_Frac

ret

Dec_Frac EndP

; -------------------------------------

ID_Length equ 6 ;学号长度

Info_Students Struc ; 学生信息结构类型

ID_Student db ID_Length dup() ;学号

Score_Student db ;成绩

Info_Students EndS

; -------------------------------------

Students equ 20 ;学生人数

Prompt_Str db 'Student ID',2 dup(20h) ;学号标题字符串

db 'Score',CR,LF ;成绩标题字符串

db 10 dup('-'),2 dup(20h)

db 5 dup('-'),CR,LF,'$'

Score_Tab db 6 dup(0) ; 各分数段计数

prompt_Res db '00---59: $'

prompt_Ave db CR,LF,'Average: $' ;提示显示平均分

Buffer_Data db ,,ID_Length+2 dup() ;学号输入缓冲区

Press_Key db CR,LF,CR,LF,'Press any key to exit$'

Start: push cs

pop ds

push cs

pop es ;使数据段、附加段与代码段同段

mov @@Digits,3 ;十进制数字位数

mov @@Type_Data,'B' ;保存的数据类型。B=字节类型,W=字类型

; -------------------------------------

; 显示学号、成绩标题,提示输入学生信息

Output Prompt_Str

; -------------------------------------

; 输入学号、成绩

lea di,Score_Table ;学号、成绩存放地址

mov cx,Students ;学生人数

cld

Input_Info: push cx

call GetCursor ;取光标位置

push di

lea di,Buffer_Data[2]

mov cx,(ID_Length+2)/2

mov ax,2020h ;填充空格

rep stosw

pop di

mov Buffer_Data,ID_Length+1 ;允许输入的最多字符数

lea dx,Buffer_Data ;学号输入缓冲区地址

mov ah,0ah

int 21h

lea si,Buffer_Data[2]

mov cx,ID_Length ;学号字符数

rep movsb ;写入学生信息缓冲区

add Cursor_Col,12

call SetCursor ;置光标位置

call Input_Digit ;输入成绩

call Output_CTLF ;输出一个回车、换行

pop cx

loop Input_Info ;输入下一名学生信息

; -------------------------------------

; 建立学生信息链表

mov cx,Students ;学生人数

mov si,di ;保存链表地址

lea ax,Score_Table ;学生信息起始地址

@@L1: stosw ;保存学生信息地址

add ax,type Info_Students ;每名学生信息所占内存容量

loop @@L1

; -------------------------------------

; 用冒泡排序法按成绩降序排序

mov cx,Students ;学生人数

push si ;入栈保存链表地址

push cx ;保存学生人数

dec cx ;准备用冒泡排序法排序

@@Sorting: push cx ;入栈保存外循环次数

push si ;入栈保存数组地址

@@Compare: push si

pop di ;当前数组元素地址赋给目的变址寄存器,以备交换之用

lodsw ;将当前学生信息地址读入AX

mov bx,ax

mov al,[bxScore_Student] ;将当前学生成绩读入AL

mov bx,[si] ;相邻的下一个学生信息地址

cmp al,[bxScore_Student] ;当前学生成绩与相邻的下一个学生成绩相比较

jae @@NextOne ;若大于或等于,不作数据交换,处理下一个数组元素

mov ax,[di] ;若小于,读入当前学生信息链表节点

xchg ax,[si] ;交换链表元素

mov [di],ax ;保存数值较大者节点地址

@@NextOne: loop @@Compare ;处理下一个数组元素

pop si ;数组地址出栈

pop cx ;外循环次数出栈

loop @@Sorting ;下一趟比较

call Output_CTLF

; -----------------------------------------

; 按成绩降序显示所有学生信息

Output Prompt_Str ;显示学生信息标题

pop cx ;d出学生人数

pop si ;d出链表地址

xor bx,bx ;总成绩初值

@@List_Info: push cx ;保存学生人数

call GetCursor ;取光标位置

lodsw ;读入链表的一个节点

push si ;入栈保存链表地址

mov si,ax

push si ;入栈保存学生信息地址

lea si,[siID_Student] ;学号地址

mov cx,ID_Length ;学号字符串长度

@@Dsip_ID: lodsb ;读入一个字符

cmp al,0dh ;回车符?

jz @@L2 ;是,学号显示结束

mov dl,al

call Output_Chr ;显示一个字符

loop @@Dsip_ID ;下一个字符

@@L2: add Cursor_Col,12

call SetCursor ;置光标位置

pop si ;d出学生信息地址

lea si,[siScore_Student] ;成绩地址

lodsb ;读入成绩

xor ah,ah

add bx,ax ;累加总成绩

call Statics_Score ;统计各分数段人数

call Dec_ASCII ;把AX中的二进制无符号数转换成显式的十进制ASCII码,并送显示屏显示

call Output_CTLF

pop si ;d出链表地址

pop cx ;d出学生人数

loop @@List_Info ;下一个节点(学生信息)

mov al,Score_Tab[5] ;取100分人数

add Score_Tab[4],al ;加到90-100分数段

; -------------------------------------

push bx ;入栈保存总分

call Output_CTLF

call Output_CTLF

mov bl,59h

mov cx,5

lea si,Score_Tab ;各分数段计数数组首地址

lea dx,prompt_Res ; 统计结果字符串地址

List_Res: mov ah,9 ;显示分数段提示信息

int 21h

lodsb ;读入计数值

xor ah,ah

call Dec_ASCII ; 显示统计结果

call Output_CTLF ;输出一个回车、换行

mov al,bl

inc al

daa

mov bl,al

push cx

mov cl,4

xor ah,ah

shl ax,cl

shr al,cl

or ax,3030h

xchg ah,al

mov WORD ptr Prompt_Res,ax

mov al,bl

add al,9

mov bl,al

xor ah,ah

shl ax,cl

shr al,cl

or ax,3030h

xchg ah,al

mov WORD ptr Prompt_Res[5],ax

pop cx

loop List_Res

; -------------------------------------

; 计算并显示平均分

call Output_CTLF

call Output_CTLF

Output prompt_Ave ;提示显示平均分

pop ax ;总分出栈

mov bx,Students ;学生人数

div bl ;平均分取整数部分

mov bh,ah ;保存余数

xor ah,ah

call Dec_ASCII ;显示平均分

mov ah,bh ;余数

mov bh,bl ;除数

mov cx,2 ;保留小数位数

call Dec_Frac ;把AL中的二进制无符号数作为小数转换成显式的十进制ASCII码

; -------------------------------------

Exit_Proc: Output Press_Key ;提示 *** 作完成,按任意键结束程序

mov ah,1

int 21h

mov ah,4ch ;结束程序

int 21h

Score_Table: ;学生成绩存储区

Code ENDS

END Start ;编译到此结束

在我们springboot项目中使用的是 elasticsearch-rest-high-level-client这个ES官方推荐的客户端

当有需求批量删除过期数据一开始使用的是deleteByQuery方法,在要删除的数据比较少的时候没问题,达到几十万条的时候会报 socket超时异常,但是命令不会中断,仍然会执行完,把我们需要delete的数据删完,就是看不到结果,

这时候我们可以

很明显最后一种最合理,作为一个有追求的程序员看不见程序运行结果怎么呢

这个时候我们可以用deleteByQueryAsync :官方文档提供异步调用方式,用listener监听返回结果

监听类很简单,实现 ActionListener<BulkByScrollResponse>接口 重写两个方法一个接受成功,一个接受失败

成功的结果长这个样子

重点是删除条数 和 执行批次, 批次=影响数据量/设置的批次大小+1

同理 批量select insert update 都有async异步调用的方法。

#include<iostream>

#include<stdlibh>

#include<stringh>

#include<malloch>

#define INIT_SIZE 10

#define INCRE_SIZE 10

#define SUBJECT_NUM 3

#define LEN 3

void show_Start();

void show_Table();

void addRecord();

void Info_delete();

void deleteRecord();

void delete_Num(int);

void delete_Name(char tarName[]);

void Info_modify();

void modifyRecord();

void modify_Num(int);

void modify_Name(char[]);

void Info_query();

void queryRecord();

void query_Num(int);

void query_Name(char[]);

void display();

void quit();

void menu_CMD();

char subject[SUBJECT_NUM] = {"高代","数分","C语言"};

struct STUDENT

{

int num;

char name[20];

char sex;

float score[SUBJECT_NUM];

};

//struct STUDENT stu[LEN + 1];

//STUDENT record = (STUDENT)malloc(sizeof(STUDENT)INIT_SIZE);

int static stuNum = 0;

//先暂时定义三个学生吧

STUDENT record = (STUDENT)malloc(sizeof(STUDENT)INIT_SIZE);;

int main()

{

//record = (STUDENT)malloc(sizeof(STUDENT)INIT_SIZE);

//STUDENT record = (STUDENT)malloc(sizeof(STUDENT)INIT_SIZE);

/

record[1]num = 1001;

strcpy(record[1]name,"Jason");

record[1]sex = 'M';

record[1]score[0] = 850;

record[1]score[1] = 900;

record[1]score[2] = 950;

record[2]num = 1002;

strcpy(record[2]name,"Jerry");

record[2]sex = 'M';

record[2]score[0] = 850;

record[2]score[1] = 900;

record[2]score[2] = 950;

record[3]num = 1003;

strcpy(record[3]name,"Jessie");

record[3]sex = 'F';

record[3]score[0] = 850;

record[3]score[1] = 900;

record[3]score[2] = 950;

/

/

Info_modify();

int key;

cout<<"请输入您的选择 : ";

cin>>key;

if(key == 1)

{

int targetNum;

cout<<"请输入您欲修改的学生的学号 : ";

cin>>targetNum;

modify_Num(targetNum);

cout<<endl;

display();

}

if(key == 2)

{

char targetName[20];

cout<<"请输入您欲修改学生的姓名 : ";

cin>>targetName;

modify_Name(targetName);

cout<<endl;

display();

}

if(key == 3)

{

exit(0);

}

/

show_Start();

menu_CMD();

return 0;

}

//修改完后还应该显示

void show_Start()

{

//cout<<endl;

cout<<" "<<endl;

cout<<" 这是一个 "<<endl;

cout<<" 学生成绩管理系统 "<<endl;

cout<<" 可以对学生成绩进行管理 "<<endl;

cout<<" 欢迎大家使用 "<<endl;

cout<<" Made by Jason "<<endl;

cout<<" "<<endl;

}

// 显示表头信息,即是 : 学号,姓名,性别,高代,数分,C语言

void show_Table()

{

cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"性别";

cout<<"\t"<<subject[0]<<"\t"<<subject[1]<<"\t"<<subject[2];

cout<<endl;

}

void menu_CMD()

{

int key;

while(1)

{

cout<<"1 增加学生信息"<<endl;

cout<<"2 删除学生信息"<<endl;

cout<<"3 修改学生信息"<<endl;

cout<<"4 查询学生信息"<<endl;

cout<<"5 显示学生信息"<<endl;

cout<<"6 退出"<<endl;

cout<<"请输入您的选择 : ";

cin>>key;

while(1)

{

if((key < 1)||(key > 6))

{

int key;

cout<<"您的输入有误,请重新输入!"<<endl;

cout<<"请选(1 - 5) : ";

cin>>key;

}

else

{

break;

}

}

switch(key)

{

case 1:

addRecord();

break;

case 2:

deleteRecord();

break;

case 3:

modifyRecord();

break;

case 4:

queryRecord();

break;

case 5:

display();

break;

case 6:

quit();

break;

}

}

}

///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////

//增加学生信息

void addRecord()

{

if(stuNum == 0)

{

cout<<"原来没有记录,现在建立新表!"<<endl;

stuNum++;

}

else

{

cout<<"现在在当前表的末尾添加新的信息!"<<endl;

stuNum++;

}

//如果数组空间不够,重新申请空间

if(stuNum > INIT_SIZE)

{

cout<<"内存空间不够,现在重新申请新的内存空间!"<<endl;

record = (STUDENT)realloc(record,(INIT_SIZE + INCRE_SIZE)sizeof(STUDENT));

cout<<"空间申请完成!"<<endl;

}

cout<<"您现在要添加一组新的信息,您确定吗"<<endl;

cout<<"请输入您的选择(Y/N) : ";

char choi;

cin>>choi;

if((choi == 'Y')||(choi == 'y'))

{

cout<<"请输入学号 : ";

cin>>record[stuNum]num;

cout<<"请输入姓名 : ";

cin>>record[stuNum]name;

cout<<"请输入性别(M为男,F为女) : ";

cin>>record[stuNum]sex;

int i;

for(i = 0;i < SUBJECT_NUM;i++)

{

cout<<"请输入"<<subject[i]<<"的成绩 : ";

cin>>record[stuNum]score[i];

}

}

if((choi == 'N')||(choi == 'n'))

{

cout<<"退出添加新学生信息!"<<endl;

cout<<endl;

}

cout<<"现在已经有"<<stuNum<<"条学生的信息了!"<<endl;

cout<<endl;

}

//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////

//删除信息 晚上完成

//显示deleteRecord的表头信息

void Info_delete()

{

cout<<"请输入删除方式 : "<<endl;

cout<<"1 按学号删除"<<endl;

cout<<"2 按姓名删除"<<endl;

cout<<"3 退出删除"<<endl;

}

//删除学生的信息,包含两个子函数

void deleteRecord()

{

int key;

cout<<endl;

Info_delete();

cout<<"请输入您的选择 : ";

cin>>key;

if(key == 1)

{

int targetNum;

cout<<"请输入您欲删除学生的学号 : ";

cin>>targetNum;

//按学号删除

delete_Num(targetNum);

cout<<endl;

}

if(key == 2)

{

char targetName[20];

cout<<"请输入您欲删除学生的姓名 : ";

cin>>targetName;

//按姓名删除

delete_Name(targetName);

cout<<endl;

}

if(key == 3)

{

while(1)

{

menu_CMD();

}

}

}

//按学号删除学生信息

//只用完成删除 *** 作,而不必输出 输出的 *** 作可以在主菜单中进行

void delete_Num(int tarNum)

{

int i;

for(i = 1;i <= stuNum;i++)

{

if(record[i]num == tarNum)

{

//删除还要分两种情况讨论

//1 欲删除的学生信息是最后一位

//2 欲删除的学生信息不是最后一位

//第一种情况,欲删除的学生是最后一位

if(i = stuNum)

{

cout<<"您所要删除的学生信息是 : "<<endl;

show_Table();

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex<<"\t"

<<record[i]score[0]<<record[i]score[1]<<"\t"<<record[i]score[2];

cout<<endl;

cout<<endl<<"删除后学生信息表为 : "<<endl;

show_Table();

for(int i = 1;i <= stuNum - 1;i++)

{

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex;

for(int j = 0;j < SUBJECT_NUM;j++)

{

cout<<"\t"<<record[i]score[j];

}

cout<<endl;

}

//显示信息应该放在后面

/

stuNum--;

cout<<"现在还剩下"<<stuNum<<"条学生的信息";

cout<<endl;

/

}

//2第二种情况,欲删除的学生不是最后一位

if(i != stuNum)

{

cout<<"您所要删除的学生信信息是 : "<<endl;

show_Table();

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex<<"\t"

<<record[i]score[0]<<"\t"<<record[i]score[1]<<"\t"<<record[i]score[2];

for(int j = i+1;j <= stuNum;j++)

{

record[j-1] = record[j];

}

//接着完成输出

cout<<endl;

cout<<"删除后学生信息表为 : "<<endl;

show_Table();

for(int i = 1;i <= stuNum-1;i++)

{

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex;

for(int j = 0;j < SUBJECT_NUM;j++)

{

cout<<"\t"<<record[i]score[j];

}

cout<<endl;

}

/

stuNum--;

cout<<"现在还剩下"<<stuNum<<"条学生的信息";

cout<<endl;

/

}

stuNum--;

cout<<"现在还是剩下"<<stuNum<<"条学生的信息";

cout<<endl;

}

}

}

/

//方法同上

void delete_Name(char tarName[])

{

int i;

for(i = 1;i <= stuNum;i++)

{

if(strcmp(record[i]name,tarName) == 0)

{

//删除还要分两种情况讨论

//1 欲删除的学生信息是最后一位

//2 欲删除的学生信息不是最后一位

//第一种情况 : 欲删除学生是最后一位

if(i = stuNum)

{

cout<<"您所要删除的学生信息是 : "<<endl;

show_Table();

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex<<"\t"

<<record[i]score[0]<<record[i]score[1]<<"\t"<<record[i]score[2];

cout<<endl;

cout<<endl<<"删除后学生信息表为 : "<<endl;

show_Table();

for(int i = 1;i <= stuNum - 1;i++)

{

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex;

for(int j = 0;j < SUBJECT_NUM;j++)

{

cout<<"\t"<<record[i]score[j];

}

cout<<endl;

}

}

//第二种情况 : 欲删除学生不是最后一位

if(i != stuNum)

{

cout<<"您所要删除的学生信信息是 : "<<endl;

show_Table();

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex<<"\t"

<<record[i]score[0]<<"\t"<<record[i]score[1]<<"\t"<<record[i]score[2];

//整体往前 前移一位

for(int j = i+1;j <= stuNum;j++)

{

record[j-1] = record[j];

}

cout<<endl;

//接着完成输出

cout<<"删除后学生信息表为 : "<<endl;

show_Table();

for(int i = 1;i <= stuNum-1;i++)

{

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex;

for(int j = 0;j < SUBJECT_NUM;j++)

{

cout<<"\t"<<record[i]score[j];

}

cout<<endl;

}

cout<<endl;

}

}

}

}

/

void delete_Name(char tarName[])

{

int i;

for(i = 1;i <= stuNum;i++)

{

//删除还要分两种情况讨论

//1 欲删除的学生信息是最后一位

//2 欲删除的学生信息不是最后一位

//当欲删除的学生是最后一位,直接输出前面LEN-1位学生的信息

if(strcmp(record[i]name,tarName) == 0)

{

if(i == stuNum)

{

cout<<"您所要删除的学生信息是 : "<<endl;

show_Table();

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex<<"\t"

<<record[i]score[0]<<"\t"<<record[i]score[1]<<"\t"<<record[i]score[2];

cout<<endl;

cout<<"删除后学生信息表为 : "<<endl;

show_Table();

for(int i = 1;i <= stuNum-1;i++)

{

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex;

for(int j = 0;j < SUBJECT_NUM;j++)

{

cout<<"\t"<<record[i]score[j];

}

cout<<endl;

}

/

stuNum--;

cout<<"现在还剩下"<<stuNum<<"条学生的信息";

cout<<endl;

/

}

//当欲删的学生不是最后一位,整体往前前移一位

if(i != stuNum)

{

cout<<"您所要删除的学生信息是 : "<<endl;

show_Table();

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex<<"\t";

cout<<record[i]score[0]<<"\t"<<record[i]score[1]<<"\t"<<record[i]score[2];

cout<<endl;

//整体往前前移一位

for(int j = i+1;j <= stuNum;j++)

{

record[j-1] = record[j];

}

//然后输出

cout<<endl;

cout<<"删除后学生信息表为 : "<<endl;

show_Table();

for(int i = 1;i <= stuNum-1;i++)

{

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex;

for(int j = 0;j < SUBJECT_NUM;j++)

{

cout<<"\t"<<record[i]score[j];

}

cout<<endl;

}

/

stuNum--;

cout<<"现在还剩下"<<stuNum<<"条学生的信息";

cout<<endl;

/

}

stuNum--;

cout<<"现在还剩下"<<stuNum<<"条学生的信息";

cout<<endl;

}

}

}

/

/

//显示modifyRecord的表头信息

void Info_modify()

{

cout<<"请输入修改方式 : "<<endl;

cout<<"1 按学号修改"<<endl;

cout<<"2 按姓名修改"<<endl;

cout<<"3 退出修改"<<endl;

}

//查询学生的成绩,当然里面包括两个子函数

void modifyRecord()

{

int key;

cout<<endl;

Info_modify();

cout<<"请输入您的选择 : ";

cin>>key;

//按学号修改

if(key == 1)

{

int targetNum;

cout<<"请输入您欲修改的学生的学号 : ";

cin>>targetNum;

modify_Num(targetNum);

cout<<endl;

//display();

}

//按姓名修改

if(key == 2)

{

char targetName[20];

cout<<"请输入您欲修改学生的姓名 : ";

cin>>targetName;

modify_Name(targetName);

cout<<endl;

//display();

}

//退出修改

if(key == 3)

{

while(1)

{

menu_CMD();

}

}

}

//按学号修改

void modify_Num(int tarNum)

{

int i;

for(i = 1;i <= stuNum;i++)

{

if(record[i]num == tarNum)

{

cout<<endl<<"请修改该学生的信息"<<endl;

cout<<"请输入该学生的学号 : ";

cin>>record[i]num;

cout<<"请输入该学生的姓名 : ";

cin>>record[i]name;

cout<<"请输入该学生的性别 : ";

cin>>record[i]sex;

cout<<"请输入"<<subject[0]<<"的成绩 : ";

cin>>record[i]score[0];

cout<<"请输入"<<subject[1]<<"的成绩 : ";

cin>>record[i]score[1];

cout<<"请输入"<<subject[2]<<"的成绩 : ";

cin>>record[i]score[2];

}

}

}

//按姓名修改

void modify_Name(char tarName[])

{

int i;

for(i = 1;i <= stuNum;i++)

{

if(strcmp(record[i]name,tarName) == 0)

{

cout<<endl<<"请修改该学生的信息 : "<<endl;

cout<<"请输入该学生的学号 : ";

cin>>record[i]num;

cout<<"请输入该学生的姓名 : ";

cin>>record[i]name;

cout<<"请输入该学生的性别 : ";

cin>>record[i]sex;

cout<<"请输入"<<subject[0]<<"的成绩 : ";

cin>>record[i]score[0];

cout<<"请输入"<<subject[1]<<"的成绩 : ";

cin>>record[i]score[1];

cout<<"请输入"<<subject[2]<<"的成绩 : ";

cin>>record[i]score[2];

}

}

}

///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////

//显示queryRecord的表头信息

void Info_query()

{

cout<<"请输入查询方式 : "<<endl;

cout<<"1 按学号查询"<<endl;

cout<<"2 按姓名查询"<<endl;

cout<<"3 退出查询"<<endl;

}

//查询学生信息queryRecord

void queryRecord()

{

int key;

cout<<endl;

Info_query();

cout<<"请输入您的选择 : ";

cin>>key;

if(key == 1)

{

int targetNum;

cout<<"请输入您欲查询学生的学号 : ";

cin>>targetNum;

query_Num(targetNum);

cout<<endl;

}

if(key == 2)

{

char targetName[20];

cout<<"请输入您欲查询学生的学号 : ";

cin>>targetName;

query_Name(targetName);

cout<<endl;

}

//退出查询,退回到主菜单吧

if(key == 3)

{

while(1)

{

menu_CMD();

}

}

}

//按学号查询

void query_Num(int tarNum)

{

int i;

for(i = 1;i <= stuNum;i++)

{

if(record[i]num == tarNum)

{

//如果表中有该学生信息的话,仅用输出该学生的信息即可

//输出该学生的信息

cout<<"该学生的信息如下 : "<<endl;

//显示表头信息

show_Table();

//显示该学生具体的信息

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex;

cout<<"\t"<<record[i]score[0]<<"\t"<<record[i]score[1]<<"\t"<<record[i]score[2];

cout<<endl;

}

}

}

//按姓名查询

void query_Name(char tarName[])

{

int i;

for(i = 1;i <= stuNum;i++)

{

if(strcmp(record[i]name,tarName) == 0)

{

cout<<"该学生的信息如下 : "<<endl;

show_Table();

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex;

cout<<"\t"<<record[i]score[0]<<"\t"<<record[i]score[1]<<"\t"<<record[i]score[2];

cout<<endl;

}

}

}

///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////

//先显示所有学生的信息吧

//显示record里所有学生的成绩

void display()

{

show_Table();

int i,j;

for(i = 1;i <= stuNum;i++)

{

//cout<<"学号"<<"\t"<<"姓名"<<"\t"<<"性别";

cout<<record[i]num<<"\t"<<record[i]name<<"\t"<<record[i]sex;

for(j = 0;j < SUBJECT_NUM;j++)

{

cout<<"\t"<<record[i]score[j];

}

cout<<endl;

}

cout<<endl;

}

//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////

//退出

void quit()

{

char choi;

cout<<"您确定要退出吗"<<endl;

cout<<"请输入您的选择(Y/N) : ";

cin>>choi;

if((choi == 'Y')||(choi == 'y'))

{

cout<<"现在退出学生信息管理系统"<<endl;

exit(0);

}

//如果不是退出,则接着退回到主界面

else

{

cout<<endl;

menu_CMD();

}

}

这个是原创的 在C-Free 40里跑过,可以正常运行

你可以试着跑一下,如果有什么问题可以和我联系

按SHIFT—— MODE ——2 ,选用LineIO格式,以后计算直接出来就是分数了。

科学型计算器可进行乘方、开方、指数、对数、三角函数、统计等方面的运算。科学型带有所有普通的函数,所有的函数都分布在键盘上以致于可以不用通过菜单列表来使用它们。

科学计算器支持显示24位数字,支持运算优先选择模式、进制转换功能、标准数学函数、百分比计算、方根计算、对数、次方、记忆等功能。

扩展资料:

科学计算器的其他功能:

计算器里面有一个存储器,默认状态下是空的。它能保存任意一个数值,也只能存一个值。你可以

MS:存当前显示的数值。

MR:读取存储器中的数值,并显示出来。

MC:清除已存的数据。

M-:用已存的数值减去当前显示的数值后,再将结果保存。

M+:用已存的数值加上当前显示的数值后,再将结果保存。

-科学计算器

@[toc]

分片是 Elasticsearch 在集群中分发数据的关键。

把分片想象成数据的容器。文档存储在分片中,然后分片分配到集群中的节点上。当集群扩容或缩小,Elasticsearch 将会自动在节点间迁移分片,以使集群保持平衡。

一个分片(shard)是一个最小级别“工作单元(worker unit)”,它只是保存了索引中所有数据的一部分。

这类似于 MySql 的分库分表,只不过 Mysql 分库分表需要借助第三方组件而 ES 内部自身实现了此功能。

分片可以是 主分片(primary shard) 或者是 复制分片(replica shard)

在集群中唯一一个空节点上创建一个叫做 blogs 的索引。默认情况下,一个索引被分配 5 个主分片,下面只分配 3 个主分片和一个复制分片(每个主分片都有一个复制分片):

在一个多分片的索引中写入数据时,通过路由来确定具体写入哪一个分片中,大致路由过程如下:

routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到余数 。这个在 0 到 number_of_primary_shards 之间的余数,就是所寻求的文档所在分片的位置。

这解释了为什么要在创建索引的时候就确定好主分片的数量并且永远不会改变这个数量: 因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了

索引中的每个文档属于一个单独的主分片,所以 主分片的数量决定了索引最多能存储多少数据 (实际的数量取决于数据、硬件和应用场景)。

复制分片只是主分片的一个副本,它可以 防止硬件故障导致的数据丢失,同时可以提供读请求,比如搜索或者从别的 shard 取回文档

每个主分片都有一个或多个副本分片,当主分片异常时,副本可以提供数据的查询等 *** 作。主分片和对应的副本分片是不会在同一个节点上的,所以副本分片数的最大值是 n -1(其中 n 为节点数)。

当索引创建完成的时候,主分片的数量就固定了,但是复制分片的数量可以随时调整,根据需求扩大或者缩小规模。如把复制分片的数量从原来的 1 增加到 2 :

分片本身就是一个完整的搜索引擎,它可以使用单一节点的所有资源。 主分片或者复制分片都可以处理读请求——搜索或文档检索,所以数据的冗余越多,能处理的搜索吞吐量就越大。

对文档的新建、索引和删除请求都是写 *** 作,必须在主分片上面完成之后才能被复制到相关的副本分片,ES 为了提高写入的能力这个过程是并发写的,同时为了解决并发写的过程中数据冲突的问题,ES 通过乐观锁的方式控制,每个文档都有一个 _version (版本)号,当文档被修改时版本号递增。一旦所有的副本分片都报告写成功才会向协调节点报告成功,协调节点向客户端报告成功。

ES 集群中每个节点通过路由都知道集群中的文档的存放位置,所以每个节点都有处理读写请求的能力。

在一个写请求被发送到某个节点后,该节点即为协调节点,协调节点会根据路由公式计算出需要写到哪个分片上,再将请求转发到该分片的主分片节点上。假设 shard = hash(routing) % 4 = 0 ,则过程大致如下:

写入磁盘的倒排索引是不可变的,优势主要表现在:

当然,不可变的索引有它的缺点:

在全文检索的早些时候,会为整个文档集合建立一个大索引,并且写入磁盘。只有新的索引准备好了,它就会替代旧的索引,最近的修改才可以被检索。这无疑是低效的。

因为索引的不可变性带来的好处,那如何在保持不可变同时更新倒排索引?

答案是,使用多个索引。 不是重写整个倒排索引,而是增加额外的索引反映最近的变化。 每个倒排索引都可以按顺序查询,从最老的开始,最后把结果聚合。

这就引入了 段 (segment)

分片下的索引文件被拆分为多个子文件,每个子文件叫作 , 每一个段本身都是一个倒排索引,并且段具有不变性,一旦索引的数据被写入硬盘,就不可再修改。

段被 写入到磁盘 后会生成一个 提交点 ,提交点是一个用来记录所有提交后段信息的文件。一个段一旦拥有了提交点,就说明这个段只有读的权限,失去了写的权限。相反,当段在内存中时,就只有写的权限,而不具备读数据的权限,意味着不能被检索。

在 Lucene 中的索引(Lucene 索引是 ES 中的分片,ES 中的索引是分片的集合)指的是段的集合,再加上提交点(commit point),如下图:

在底层采用了分段的存储模式,使它在读写时几乎完全避免了锁的出现,大大提升了读写性能。

索引文件分段存储并且不可修改 ,那么新增、更新和删除如何处理呢?

ES 是怎么做到 近实时 全文搜索?

磁盘是瓶颈。提交一个新的段到磁盘需要 fsync *** 作,确保段被物理地写入磁盘,即时电源失效也不会丢失数据。但是 fsync 是昂贵的,严重影响性能,当写数据量大的时候会造成 ES 停顿卡死,查询也无法做到快速响应。

所以 fsync 不能在每个文档被索引的时就触发,需要一种更轻量级的方式使新的文档可以被搜索,这意味移除 fsync 。

为了提升写的性能,ES 没有每新增一条数据就增加一个段到磁盘上,而是采用 延迟写 的策略。

每当有新增的数据时,就将其先写入到内存中,在内存和磁盘之间是文件系统缓存,当达到默认的时间(1秒钟)或者内存的数据达到一定量时,会触发一次刷新(Refresh),将内存中的数据生成到一个新的段上并缓存到文件缓存系统 上,稍后再被刷新到磁盘中并生成提交点

这里的内存使用的是ES的JVM内存,而文件缓存系统使用的是 *** 作系统的内存。新的数据会继续的被写入内存,但内存中的数据并不是以段的形式存储的,因此不能提供检索功能。由内存刷新到文件缓存系统的时候会生成了新的段,并将段打开以供搜索使用,而不需要等到被刷新到磁盘。

在 Elasticsearch 中,这种写入和打开一个新段的轻量的过程叫做 refresh (即内存刷新到文件缓存系统)。默认情况下每个分片会每秒自动刷新一次。 这就是为什么说 Elasticsearch 是近实时的搜索了:文档的改动不会立即被搜索,但是会在一秒内可见。

也可以手动触发 refresh。 POST /_refresh 刷新所有索引, POST /index/_refresh 刷新指定的索引:

没用 fsync 同步文件系统缓存到磁盘,不能确保电源失效,甚至正常退出应用后,数据的安全。为了 ES 的可靠性,需要确保变更持久化到磁盘。

虽然通过定时 Refresh 获得近实时的搜索,但是 Refresh 只是将数据挪到文件缓存系统,文件缓存系统也是内存空间,属于 *** 作系统的内存,只要是内存都存在断电或异常情况下丢失数据的危险。

为了避免丢失数据,Elasticsearch添加了 事务日志(Translog) ,事务日志记录了所有还没有持久化到磁盘的数据。

有了事务日志,过程现在如下:

事务日志记录了没有 flush 到硬盘的所有 *** 作。当故障重启后,ES 会用最近一次提交点从硬盘恢复所有已知的段,并且从日志里恢复所有的 *** 作。

在 ES 中,进行一次提交并删除事务日志的 *** 作叫做 flush 。分片每 30 分钟,或事务日志过大会进行一次 flush *** 作。 flush API 也可用来进行一次手动 flush , POST/ _flush 针对所有索引有效, POST /index/_flush 则指定的索引:

通常很少需要手动 flush ,通常自动的就够了。

总体的流程大致如下:

由于自动刷新流程每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。每一个段都会消耗文件句柄、内存和 cpu 运行周期。更重要的是,每个搜索请求都必须轮流检查每个段然后合并查询结果,所以段越多,搜索也就越慢。

ES 通过后台合并段解决这个问题。小段被合并成大段,再合并成更大的段。这时旧的文档从文件系统删除的时候,旧的段不会再复制到更大的新段中。合并的过程中不会中断索引和搜索。

段合并在进行索引和搜索时会自动进行,合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中,这些段既可以是未提交的也可以是已提交的。

合并结束后老的段会被删除,新的段被 flush 到磁盘,同时写入一个包含新段且排除旧的和较小的段的新提交点,新的段被打开可以用来搜索。

1 全文搜索引擎Elasticsearch,这篇文章给讲透了

2ElasticSearch 权威指南》

ES还具有分布式特点,它可以将数据分布在多个节点上进行存储和处理,提高了数据的可靠性和可用性。ES还提供了多种安全功能,例如身份验证、访问控制等,保障了数据的安全性。

总之,ES是一款功能强大、易于使用、高效可扩展的搜索引擎软件。它在大数据分析、日志分析、企业搜索等领域得到了广泛的应用,成为了数据处理和分析的重要工具。

总之,ES是一款功能强大、易于使用、高效可扩展的搜索引擎软件。它在大数据分析、日志分析、企业搜索等领域得到了广泛的应用,成为了数据处理和分析的重要工具。

ES还具有分布式特点,它可以将数据分布在多个节点上进行存储和处理,提高了数据的可靠性和可用性。ES还提供了多种安全功能,例如身份验证、访问控制等,保障了数据的安全性。

ES的特点之一是可扩展性,它支持横向扩展,可以通过增加节点来提高搜索和分析的性能。ES还提供了多种插件,例如Kibana、Logstash等,可以方便地进行数据可视化和数据处理。

ES还具有分布式特点,它可以将数据分布在多个节点上进行存储和处理,提高了数据的可靠性和可用性。ES还提供了多种安全功能,例如身份验证、访问控制等,保障了数据的安全性。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/12457292.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-23
下一篇2023-05-23

发表评论

登录后才能评论

评论列表(0条)

    保存