算法总结
考研
1.已知2个有序表,A[0,…n-1],B[0,…m-1]尝试写一个算法将他们归并为有序表C[0,…m+n-1]
typedef struct{
ElementType data[Maxsize];
int length
}Sqlist
bool Merge(Sqlist A,Sqlist B,Sqlist &C){
if(A.length+B.length>C.length)
return false;
int i =0,j=0,k=0;
while(i<A.length&&j<B.length){
if(A.data[i]<B.data[j]){
C.data[k++]=A.data[i++]
}else {
C.data[k++]=B.data[j++]
}
}
while(i<A.length)
C.data[k++]=A.data[i++];
while(j<B.length)
C.data[k++]=B.data[j++];
C.length=k;
return true;
}
2.从顺序标中删除具有最小元素的(假设唯一)并由函数删除被删除的元素的值,空出的位置有最后一个元素填补,若顺序表为空则显示错误信息并推出
int Del_MIN(Sqlist &L){
if(l.length==0){
printf("空表")
}
int min =0 ,locate=0;
min=L.data[0];
for(int i=1;i<L.length;i++){
if(min>L.data[i]){
min=L.data[i];
locate=i;
}
}
L.data[locate]=L.data[L.length-1];
return min;
}
3.将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)
void Reverse(Sqlist &L){
int temp;
for (int i=0;i<L.length/2;i++){
temp=L.data[i];
L.data[i]=L.data[L.length-i-1];
L.data[L.length-i-1]=temp;
}
}
排序
1.插入排序
void insert(int A[],int n){
int i,j;
for(i=2;i<=n;i++){
if(A[i]<A[i-1]){
A[0]=A[i]
for(j=i-1;A[0]<A[j];--j){
A[j+1]=A[j];
}
A[j+1]=A[0];
}
}
}
2.折半插入排序
void InsertSort(int A[],int n){
int i,j,low,high,mid;
for(i=2;i<=n;i++){
if(A[i]<A[i-1]){
low=1,high=i-1;
while(low<=high){
mid=(low+high)/2;
if(A[mid]>A[0]){
high=mid-1;
}else{
low=mid+1;
}
}
for(j=i-1;j>=high+1;--j)
A[j+1]=A[j]
A[high+1]=A[0]
}
}
}
希尔排序
public int[] shellSort(int A[],int n){
int dk,i,j;
for(dk=n/2;dk>=1;dk=dk/2){
for(i=dk+1;i<=n;i++){
if(A[i]<A[i-dk]){
A[0]=A[i];
for(j=i-dk;j>0&&A[j]>A[0];j=j-dk)
A[j+dk]=A[j];
A[j+dk]=A[0];
}
}
}
return A;
}
冒泡排序
void BubbleSort(int A[],int n){
for(i=0;i<n-1;i++){
flag=false;
for(j=n-1;j>i;j--){
if(A[j-1]>A[j]){
int temp=A[j-1];
A[j-1]=A[j];
A[j]=temp;
flag=true;
}
if(flag==false)
return;
}
}
}
快速排序
void QuickSort(int A[],int low,int high){
if(low<high){
int pivotpos=Partition(A,low,high);
QuickSort(A,low,pivotpos-1);
QuickSort(A,pivotpos+1,high);
}
}
public int Partition(int A[],int low,int high){
int pivot=A[low];
while (low<high){
while (low <high && A[pivot]<A[high])
high--;
while (low<high && A[pivot]>A[low])
low++;
}
A[low]=pivot;
return low;
}
选择排序
void SelectSort(int A[],int n){
for(int i=0;i<n-1;i++){
min=i;
for(int j=i+1;j<n;j++){
if(A[j]<A[min])
min=j;
}
if(min!=i){
int temp=A[min];
A[min]=A[i];
A[i]=temp;
}
}
}
堆排序
public void HeapSort(int A[],int len){
BuildMaxHeap(A,len);
for(int i=len;i>1;i--){
int temp=A[1];
A[1]=A[i];
A[i]=temp;
HeadAdjust(A,1,i-1);
}
}
public void BuildMaxHeap(int A[],int len){
for(int i=len/2;i>0;i--){
HeadAdjust(A,i,len);
}
}
public void HeadAdjust(int A[],int k,int len){
//函数headAdjust将元素k为根的字数进行调整
A[0]=A[k];
for(int i=2*k;i<len;i*=2){
if(i<len && A[i]<A[i+1]){
i++;
}
if(A[0]>=A[i]) break;
else {
A[k]=A[i];
k=i;
}
}
A[k]=A[0];
}
归并排序
void Merge(int A[],int low,int mid,int high){
int B[]=new int[A.length];
for(int k=low ;k<=high;k++)
B[k]=A[k]
for(int i=low,j=mid+1,k=i;i<mid&&j<high;k++){
if(B[j]>=A[i]){
A[k]=B[j++];//将较小的值复制到A中
}else{
A[k]=B[i++];
}
}
while(i<=mid) A[k++]=B[i++];
while(j<=high) A[k++]=B[j++];
}
void MergeSort(int A[],int low,int high){
if(low<high){
int low=(low+high)/2;
MergeSort(A,low,mid);
MergeSort(A,mid+1,high);
Merge(A,low,mid,high)
}
}
信号量
生产者消费者
semaphore mutex=1; //临界区互斥信号量
semaphore empty=n; //空闲缓存区
semaphore full=0; //缓冲区初始化为空
producer(){
while(1){
P(empty);
P(mutex);
add next to buffer;
V(mutex);
V(full);
}
}
consumer(){
while(1){
P(full);
P(mutex);
remove an item from buffer;
V(mutex);
V(empty);
}
}
爸妈儿女问题
问题描述:桌子上有一个盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈转向盘子中放橘子,儿子专门等着盘子里面中的橘子,女儿专门吃盘子里面的苹果,只有盘子为空时,爸爸或者妈妈才可以向盘子中放入一个水果,仅当盘子中有自己需要的水果时,儿子或者女儿可以从盘中取出。
问题分析:爸爸和妈妈时互斥关系。爸爸和女儿时同步,妈妈和儿子时同步,而且这两对关系必须练起来。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-utlTBwWX-1618061161406)(img/爸妈女儿.png)]
semaphore plate=1;//互斥信号量,代表盘子
semaphore apple=0,orange=0;//同步信号量
dad(){
while(1){
P(plate);
put the apple on the plate;
V(apple);
}
}
mom(){
while(1){
P(plate);
put the orange on the plate;
V(apple);
}
}
son(){
while(1){
P(orange);
take an orange from the plate;
V(plate);
}
}
daughter(){
while(1){
P(apple);
take apple from the plate;
V(plate);
}
}
读者-写者问题
问题描述:有读者和写着两组并发进程,共享一个文件,当两个或者以上的读进程同时访问共享数据时不会产生副作用,但是若某个写进程或者其他进程(读进程或者写进程)同时访问两个共享数据时则可能导致数据不一致错误。因此要求:1.允许多个读者同时对文件执行读操作。2.只允许一个写者往文件中写信息。3.任意写着在完成写操作完成之前不允许其他读者或者写着工作。4.写着执行写操作前,应让已有读者和写着全部退出。
问题分析:读者和写着是互斥的,写着和写着也是互斥的,而读者和读者不存在互斥问题
int count=0; //代表读者数量
semaphore mutex=1; //互斥信号量,保护更新count变量时的互斥
semaphore rw=1; //互斥信号量,读者和写着互斥
writer(){
while(1){
P(rw);
writing;
V(rw);
}
}
reader(){
while(1){
P(mutex);
if(count==0){
P(rw);
}
count++;
V(mutex);
reading;
P(mutex);
count--;
if(count==0){
V(rw);
}
V(mutex);
}
}
哲学家进餐问题
semaphore chopstick[5]={1,1,1,1,1};//初始化信号量
semaphore mutex=1;//设置去筷子的信号量;
pi(){
do(){
P(mutex);
P(chopstick[i]);
P(chopstick[(i+1)%5]);//一共有5根筷子
V(mutex)
eat;
V(chopstick[i]);
V(chopstick[(i+1)%5]);
}while(1)
}
吸烟者问题
问题描述:假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停的卷烟并抽调,但是卷起并抽调一支烟,抽烟者需要三种材料:烟草,纸和胶水。三个抽烟者中,第一个拥有烟草,第二个拥有纸,第三个拥有胶水。供应者进程无限的提供三种材料,供应者每次将两种材料放在桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽调它,并给供应者一个信号告诉已完成,此时供应者就会把剩下另外两种材料放到桌子上,入此重复(让三个抽烟者轮流的抽烟)
问题分析:供应者与三个抽烟者分别时同步关系,由于供应者无法同时满足两个及其以上的抽烟者,三个抽烟者对抽烟这个动作时互斥的关系;
int random;//存储随机数
semaphore offer1=0;//定义信号量对应烟草和纸的组合
semaphore offer2=0;//定义信号量对应烟草和胶水的组合
semaphore offer3=0;//定义信号量对应胶水和纸的组合
semaphore finish=0;//代表抽烟是否完成
process p1(){//供应者
while(1){
random=任意一个正数
random=random%3;
if(random==0){
V(offer1);
}else if(random==1){
V(offer2);
}else if(random==2){
V(offer3);
}
任意两种材料方才桌子上;
P(finish);
}
}
process P2(){
while(1){
P(offer1)
抽烟;
V(finish)
}
}
process P3(){
while(1){
P(offer2)
抽烟;
V(finish)
}
}
process P3(){
while(1){
P(offer3)
抽烟;
V(finish)
}
}
e finish=0;//代表抽烟是否完成
process p1(){//供应者
while(1){
random=任意一个正数
random=random%3;
if(random0){
V(offer1);
}else if(random1){
V(offer2);
}else if(random==2){
V(offer3);
}
任意两种材料方才桌子上;
P(finish);
}
}
process P2(){
while(1){
P(offer1)
抽烟;
V(finish)
}
}
process P3(){
while(1){
P(offer2)
抽烟;
V(finish)
}
}
process P3(){
while(1){
P(offer3)
抽烟;
V(finish)
}
}