1、问题描述
给一个n个元素的线性表A,对于每个数Ai,找到它之前的数中,和它最接近的数。
即对于每个i,求 Ci = min{ |Ai -Aj | | 1<= j < i}
1.2算法分析
有两种思路可以解决上诉问题:
(1) 遍历整个线性表,对每个元素 A[i] ,遍历 A[0] - A[i-1] , 求出与 A[i] 绝对值最小的元素。这种方法的效率为O(n^2)。
(2)先对线性表 A 进行排序, 将结果构造成双向链表 L 。反向遍历 A,将每个元素 A[i] , 比较 A[i] - A[i-1] 和A[i+1] - A[i] ,取两者中与 A[ i ] 更接近的,即是 A[ i ] 之前的数中与 A[ i ]最接近的。然后 将A[i] 从L中删去。则双向链表中剩下的元素就是 A[i] 前面的元素。这种方法的效率可以达到O(nlogn)。
1.3 算法过程图解
1.4 思路2算法实现
首先,需要的一个双向链表作为辅助,定义双向链表结构如下:
struct LNode{struct LNode* next;struct LNode* prev;int key;
};
给链表添加一些操作,来支持解决问题:
#include <stdio.h>
#include <malloc.h>
#include "lcl.h"//从数组里创建链表
struct LNode* create_list_from_array( int* array,int array_length)
{struct LNode* head,*prev_node=NULL,*node;int i=0;for(i=0;i<array_length;i++){node=(struct LNode*)malloc(LEN);node->key=array[i];node->next=NULL;node->prev=prev_node;if(prev_node==NULL) //创建第一个结点时执行 {head=node; }else{prev_node->next=node;} prev_node=node;}return head;
}//求与node结点值最接近的结点,并打印
void get_near(struct LNode* node)
{int a=0,b=0,c=0,ab=0,bc=0,near;if(node->prev==NULL&&node->next==NULL) {printf("no other num before %d \n",node->key);return;}if(node->prev==NULL){printf("brefore and the most nearest %d num is:%d\n",node->key,node->next->key);return; }if(node->next==NULL){printf("brefore and the most nearest %d num is:%d\n",node->key,node->prev->key);return; }a=node->prev->key;b=node->key;c=node->next->key;ab=b-a;bc=c-b;near=ab>bc?c:a;printf("brefore and the most nearest %d num is:%d\n",node->key,near);
}//从链表删除值为n的一个元素
struct LNode* delete_last_n(struct LNode* list,int n)
{struct LNode* head=list,*node=list,*prev,*curr,*next;while(node!=NULL&&node->key<n){node=node->next;}prev=node->prev;curr=node;next=node->next;get_near(node);if(prev==NULL&&next==NULL){free(curr);return NULL; }if(prev!=NULL){prev->next=next;}else{list=next;}if(next!=NULL){ next->prev=prev;}else{prev->next=NULL;}free(curr);return list;
}
然后,需要一个排序算法对线性表进行排序,这里使用到归并排序:
extern void print_array(int* array,int n);
//归并排序 void merge_array(int* array,int p,int q,int r){int l1=q-p+2,l2=r-q+1;int A[l1],B[l2]; //多加 1为最后一个元素赋最大值留着 int i=0,j=0,k=0;for(i=p,j=0;i<=q;i++,j++){A[j]=array[i];}A[j]=MAX_NUMBER;for(i=q+1,j=0;i<=r;i++,j++){B[j]=array[i];}B[j]=MAX_NUMBER;i=0,j=0,k=0;for(k=p;k<=r;k++){if(A[i]>B[j]){array[k]=B[j];j++; }else{array[k]=A[i];i++; }}
}void merge_sort(int* array,int p,int r){ //归并排序,p为计数起点,一般是0,r为数组最后序号,为n-1 if(p<r){ int q=p+(r-p)/2;merge_sort(array,p,q);merge_sort(array,q+1,r);merge_array(array,p,q,r);}
}
//初始化并运行程序
void init(int array_length)
{ int array[array_length],array2[array_length],i=0;struct LNode* list;get_iarray_scf(array,array_length); //获取输入数组 copy_array(array,array2,array_length); //保存初始数组 print_array(array,array_length); //对数组排序 merge_sort(array,0,array_length-1);//将排序结果创建双向链表 list=create_list_from_array(array,array_length);// 从后往遍历输入数组,依次从双向链表删除 for(i=array_length-1;i>=0;--i){list=delete_last_n(list,array2[i]);}
}
附录:
1、代码
2、参考教程