求逆序数
归并排序
#include<stdio.h>//归并排序
#include<stdlib.h>
#define n 10
mergesort(int *a,int left,int right,int *temp)
{
if(left>=right)return ;//递归结束条件,当只有一个时没必要排序
int mid=(left+right)/2;
mergesort(a,left,mid,temp);//对左边区域排序
mergesort(a,mid+1,right,temp);//对右边区域排序
int begin1=left,end1=mid;//标记左边第一元素和最后一个元素
int begin2=mid+1,end2=right;//同理
int i=left;//便于辅助函数拷贝
while(begin1<=end1&&begin2<=end2)//左右两边相比,取小的那个拷贝到temp函数
{
if(a[begin1]>=a[begin2])
{
temp[i]=a[begin2++];
}
else
{
temp[i]=a[begin1++];
}
i++;
}
while(begin1<=end1)//考虑到左右两边标记未等于各自末标记点,将其拷贝,此时的是有序的数列,直接拷贝
{
temp[i++]=a[begin1++];
}
while(begin2<=end2)//同理
{
temp[i++]=a[begin2++];
}
for(i=left;i<=right;i++)//拷贝到原数组
{
a[i]=temp[i];
}
}
int main()
{
int *tem=(int *)malloc(sizeof(int )*n);//动态分配空间给辅助数组
int a[n]={2,3,6,4,1,8,5,7,2,10};
mergesort(a,0,9,tem);//调用归并排序函数进行排序
free(tem);//释放内存
for(int i=0;i<n;i++)
{
printf("%d ",a[i]);
}
return 0;
}
归并排序的时间复杂度为nlog(n),相对于快速排序是个不错的选择,主要利用分冶法和归并法,归并是分冶的倒叙,只不过归并时候进行了一一比较排序和,利用递归的方法进行排序,主要操作集中在归并上,利用到了辅助数组来存放临时排放好的数,最后拷贝到原数组。
本题目的求逆序数可以用归并排序求解,在归并排序的主体代码块中的相比较时插入sum+=(mid-begin1+1);即可求出逆序数有几个
在这里插入代码片#include<stdio.h>//归并排序
#include<stdlib.h>
#define n 5
int sum=0;
mergesort(int *a,int left,int right,int *temp)
{
if(left>=right)return ;//递归结束条件,当只有一个时没必要排序
int mid=(left+right)/2;
mergesort(a,left,mid,temp);//对左边区域排序
mergesort(a,mid+1,right,temp);//对右边区域排序
int begin1=left,end1=mid;//标记左边第一元素和最后一个元素
int begin2=mid+1,end2=right;//同理
int i=left;//便于辅助函数拷贝
while(begin1<=end1&&begin2<=end2)//左右两边相比,取小的那个拷贝到temp函数
{
if(a[begin1]>=a[begin2])
{
temp[i]=a[begin2++];
sum+=(mid-begin1+1);
}
else
{
temp[i]=a[begin1++];
}
i++;
}
while(begin1<=end1)//考虑到左右两边标记未等于各自末标记点,将其拷贝,此时的是有序的数列,直接拷贝
{
temp[i++]=a[begin1++];
}
while(begin2<=end2)//同理
{
temp[i++]=a[begin2++];
}
for(i=left;i<=right;i++)//拷贝到原数组
{
a[i]=temp[i];
}
}
int main()
{
int *tem=(int *)malloc(sizeof(int )*n);//动态分配空间给辅助数组
int a[n]={5,4,1,3,2};
mergesort(a,0,4,tem);//调用归并排序函数进行排序
free(tem);//释放内存
for(int i=0;i<n;i++)
{
printf("%d ",a[i]);
}
printf("\n%d",sum);
return 0;
}
由于数字长度远超计算机能表示数字最大范围,故而将竖式乘法拆分,例如·
在这里插入代码片char* multiply(char* num1, char* num2) {
int sum=0,count=0,i,j;
int x1=strlen(num1),x2=strlen(num2);
int *y=(int *)malloc(sizeof(int)*(x1+x2));
for(i=0;i<x1+x2;i++)
{
y[i]=0;//对数组赋值0,其实可以改为memset(y,0,sizeof(int)*(x1+x2));
}
for(i=x1-1;i>=0;i--)
{
for(j=x2-1;j>=0;j--)
{
y[i+j+1]+=(num1[i]-'0')*(num2[j]-'0');//关键步骤,实现上图功能
}
}
for(i=x1+x2-1;i>=1;i--)
{
y[i-1]+=y[i]/10;
y[i]=y[i]%10;//实现上图算法
}
char *result=(char *)malloc(sizeof(char)*(x1+x2+1));//开一个字符串数组为结果
while(y[count]==0&&count<x1+x2-1)//避免出现0
{
count++;
}
while(count<x1+x2)
{
result[sum++]=y[count++]+'0';
}
result[sum]='\0';//结尾添\0
return result;
}
从字符串相乘中学到了memset函数的用法,初始一块指定内存值赋值为某值。
**void *memset(void *s,int c,size_s),如假设我有一个int类型的已经动态分配内存的指针为int *value=(int *)malloc(sizeof(int)length);我想让这一内存所指向的值都赋值为1,则 memset(value,1,sizeof(int)length);就ok了
复习了链表,敲了一下带头节点和不带头节点的链表。
不带头节点的头插法,输出的数据和输入的数据顺序相反
在这里插入代码片#include<stdio.h>
#include<stdlib.h>
struct LNode
{
int data;
struct LNode *next;
};
struct LNode *head=NULL;//定义一个空的头指针
void inserthead(int num)//定义一个函数来读取数值
{
struct LNode *newNode=(struct LNode*)malloc(sizeof(struct LNode));
newNode->data=num;
newNode->next=head;
head=newNode;
}
int main()
{
int n,count=0;
while(scanf("%d",&n)!=EOF)//多组输入
{
inserthead(n);//读入数值
}
struct LNode *temp=head;//用来遍历输出数值
while(temp!=NULL)//temp不为空时运行
{
printf("%d ",temp->data);
temp=temp->next;
}
return 0;
}
不带头节点尾插法,输出的数据和输入数据的顺序一样,我觉得用这个方法不如用带头节点的尾插法。
在这里插入代码片#include<stdio.h>
#include<stdlib.h>
struct LNode
{
int data;
struct LNode *next;
};
struct LNode *head=NULL;
void insertlast(int num)
{
struct LNode *newNode=(struct LNode*)malloc(sizeof(struct LNode));
newNode->data=num;
newNode->next=NULL;
if(head==NULL)
{
head=newNode;尾插法要判断一下头指针是否为空
}
else
{
struct LNode *lastNode=head;
while(lastNode->next!=NULL)
{
lastNode=lastNode->next;
}
lastNode->next=newNode;
}
}
int main()//主函数一样
{
int n;
while(scanf("%d",&n)!=EOF)
{
insertlast(n);
}
struct LNode *temp;
temp=head;
while(temp!=NULL)
{
printf("%d ",temp->data);
temp=temp->next;
}
return 0;
}
要执行删除操作的话,可以这样,因为未带头节点,删除起来要判断在首还是不在首的删除,删除起来有点麻烦,用bool类型来传回要删除值,找到key了就删除,返回1(true),没找到就返回0(false)
在这里插入代码片bool deleteNode(struct LNode **heade,int key)
{
struct LNode *ne;
if((*heade)->data==key)
{
ne=*heade;
*heade=(*heade)->next;
free(ne);
}
else{
struct LNode *delete=*heade;
while(delete->next!=NULL)
{
if(delete->next->data==key)
{
ne=delete->next;
ne->next=delete->next;
free(ne);
return true;
}
else
{
delete=delete->next;
}
}
return false;
}
}
带头结点的头插法,输出的数据顺序和输入的相反,其头节点的数据域可以存储数据的个数,也可以不存储任何数据
在这里插入代码片#include<stdio.h>
#include<stdlib.h>
typedef struct LNode
{
int data;
struct LNode *next;
}*Linklist,LNode;
void List_Head_Insert(LNode **head,int key)
{
LNode *newnode=(LNode *)malloc(sizeof(LNode));
newnode->data=key;
newnode->next=(*head)->next;
(*head)->next=newnode;
}
int main()
{
int num;
Linklist head=(LNode*)malloc(sizeof(LNode));
head->next=NULL;
while(scanf("%d",&num)!=EOF)
{
List_Head_Insert(&head,num);
}
LNode *temp=head->next;
while(temp!=NULL)
{
printf("%d ",temp->data);
temp=temp->next;
}
return 0;
}
带头节点的尾插法,输出的数据和输入的数据相反
在这里插入代码片#include<stdio.h>
#include<stdlib.h>
typedef struct LNode
{
int data;
struct LNode *next;
}*Linklist,LNode;
void Last_insert(LNode *head,int key)
{
LNode *temp=head;
LNode *newnode=(LNode*)malloc(sizeof(LNode));
newnode->data=key,newnode->next=NULL;
while(temp->next!=NULL)
{
temp=temp->next;
}
temp->next=newnode;
}
int main()
{
int num;
Linklist head=(LNode *)malloc(sizeof(LNode));
head->next=NULL;
while(scanf("%d",&num)!=EOF)
{
Last_insert(head,num);
}
LNode *temp=head->next;
while(temp!=NULL)
{
printf("%d ",temp->data);
temp=temp->next;
}
return 0;
}
带头节点的删除法
在这里插入代码片void Node_delete(LNode *head,int number)
{
LNode *temp=head,*delete_num;
while(temp->next!=NULL)
{
if(temp->next->data==number)
{
delete_num=temp->next;
temp->next=delete_num->next;
free(delete_num);
}
else temp=temp->next;
}
}
初步学了easyx,跟着up主敲了一下代码
想要有一个图形化窗口,可以用到easyx图形库,具体引入头文件
graphics.h
在这里插入代码片#include<graphics.h>//包含easyx头文件
#include<stdio.h>
void mGraphics()
{
//RGB合成颜色 每个颜色值[0~256)左闭右开,红绿蓝
//设置填充元素
setfillcolor(RGB(10,125,36));
//设置线条颜色
setlinecolor(GREEN);
//设置线条样式
setlinestyle(PS_SOLID,5);//PS_SOLID可以转到定义看到更多线条样式
//画圆
circle(50, 50, 50);//无填充圆
//有填充圆,有边框
fillcircle(150, 50, 50);
//实心圆,没有边框
solidcircle(250, 50, 50);
}
int main()
{
//创建图形窗口
initgraph(640, 480,SHOWCONSOLE);//可以加SHOWCONSOLE,可以看到控制台消息
mGraphics();
while (1);//让创建的窗口一直显现
closegraph();//关闭图形窗口
return 0;
}
除了画图,还可以插入图片,具体实现
在这里插入代码片void drawImg()
{
//图片类型IMAGE
IMAGE imger;//不能直接赋值,必须通过函数加载
/*
文件路径问题:1,相对路径 ./源文件所在是的目录,
2,绝对路径:包含盘符的路径
*/
loadimage(&imger, "./meme.jpg");
putimage(0,0,&imger);//输出图片
}
想要在窗口中实现文字显示,具体代码
在这里插入代码片void drawStr()
{
printf("Hello word!");//输出文字到控制台,在图形窗口看不到;
/*outtextxy报错:
问题:字符集不对
解决方案:1,在字符串前面加上_T("str")
2,在字符串前面加一个大写的L
3,点击菜单栏->项目->属性->高级—>改为多字节字符集
*/
outtextxy(100, 100, "太未能阿斯蒂芬");//在图形窗口输出文字
int score = 100;
char str[10];
outtextxy(100, 120, score);//输出A,要转入字符
sprintf_s(str, "分数: %d", score);
outtextxy(100, 130, str);
setfillcolor(YELLOW);
int x = 20, y = 20;
fillrectangle(x, y, x+400, y+400);
//文字为什么不见了?注意,图形绘制是有顺序的,有层级关系
//设置文字的样式
settextstyle(30, 0, "黑体");
//把文字的背景干掉(设置背景模式为透明)
setbkmode(TRANSPARENT);ppo
//文字居中
//文字的宽度和高度
const char* strr = "吕卓远";//必须加上const
int tw = textwidth(strr);
int th = textheight(strr);
int tx = (400 - tw) / 2;
int ty = (400 - th) / 2;
settextcolor(RGB(64, 56, 78));
outtextxy(tx+x, ty+y, strr);
}
获取鼠标信息
在这里插入代码片void mouseEvent()
{
//定义保存鼠标消息的结构
MOUSEMSG msg;
//获取鼠标信息
if (MouseHit())//判断是否有鼠标消息,如果返回真1,否则0
{
msg = GetMouseMsg();
//只有点击的时候显示的话
printf("ps(%d,%d)\n", msg.x, msg.y);
//判断左键,右键,还是中键
switch(msg.uMsg)
{
case WM_LBUTTONDOWN://鼠标左键按下
printf("WM_LBUTTONDOWN");
break;
case WM_RBUTTONDOWN:
printf("WM_RBUTTONDOWN");
break;
case WM_MBUTTONDOWN:
printf("WM_MBUTTONDOWN");
break;
}
}
}