逆置算法合集

2024-4-22 星期一 下雨🌧

今天做了几道关于排序的题,发现有些相似的地方,想总结一下。给自己做一个备忘录,日后好复习用

Problem1:

1.设计一个高效的算法,将数组(也可以是顺序表)的所有元素逆置,要求算法的空间复杂度是O(1).

实例:(1,2,3,4,5)=》(5,4,3,2,1)

#算法的基本思想:
扫描数组的前半部分,对应元素交换位置即可。题目要求空间复杂度是O(1)就是不能在而外开辟空间存储元素
#代码实现:
void Reverse(int A[], int front,int end){
    int i,temp;
    int mid = (front+end)/2;
    for(i=0;i<mid;i++){
        temp = A[i];
        A[i] = A[end-i-1];
        A[end-i-1] = temp;
    }
}
这是数组的,顺序表也是一样的,就是定义上有点差距
顺序表的实现:
    #定义一个顺序表
 #define maxsize 10
 typedef struct {
     int data[maxsize];
     int length
 }Seqlist;
#初始化一下
void initSeqlist(Seqlist &L){
    L.length =5;

    for(int i=0;i<L.length;i++){
        L.data[i] =i+1;
    }
    for(int i=0;i<L.length;i++){
        printf("data[%d]=%d\n",i,L.data[i]);
    }
}
#实现代码:
void Reverse(Seqlist &L){
    for(int i=0;i<L.length/2;i++){ //这里就一个点需要注意:就是线性中的元素的位序从1开始,数组中元素的下标从0开始
        int temp = L.data[i];
        L.data[i] = L.data[L.length-i-1];//eg数组[0]<=>数组[5-0-1]数组的第一个和数组的最后一个
        L.data[L.length-i-1] = temp;
    }
}
int main() {
    Seqlist L;
    initSeqlist(L);
    transform(L);
    for(int i=0;i<L.length;i++){
        printf("data[%d]=%d\n",i,L.data[i]);
    }
    return 0;
}

总结:这个就是基础的一个(重点)数组里面所有元素位置互换,较为简单

problem2

一个数组A[m+n]中存放了两个线性表(顺序存储),Sqlist A=(a1,a2,a3…am) ,Sqlist B=(b1,b2,b3…,bn),设计一个高效的算法,将数组中两个顺序表的位置互换.示例([a1,a2,a3…am,b1,b2,b3…,bn])=>([b1,b2,b3…,bn,a1,a2,a3…am])。

#定义两个线性表存放在数组中
#define maxsize 10
#define maxSize 12

typedef struct{
    int ele[maxsize];
    int length;
}Seqlist1;

typedef struct{
    int ele[maxSize];
    int length;
}Seqlist2;

void init(Seqlist1 &L1, Seqlist2 &L2){
    L1.length = 6;
    L2.length = 8;
    int i,j;
    while(i<L1.length&&j<L2.length){
        L1.ele[i] = 1;
        L2.ele[j] = 3;
        i++; j++;
    }
}
void Reverse(int data[],int front,int end,size){
    //写一下边界判断吧,为了题目的完整性和良好的编程习惯
    if(left>=right || right > size){
        return;
    }
    int mid=(front+end)/2; //后面想了一下,如果这里采用end-front 就没有后面的mid-front这回事了,哈哈哈
    int i,temp;
    for(i=0,i<mid-front;i++){ //这里需要减front,后面会解释...
        int temp = data[front+i];
        data[front+i]=data[right-i];
        data[right-i]=temp;
    }
}

void Change(int data[],int m,int n,int size){ //参数都一样 表达的意思是一样的
    Reverse(data,0,m+n-1,size);//先全部原地逆置
    Reverse(data,0,n-1,size);//再逆置第一个数据
    Reverse(data,n,m+n-1,size);//前面之所以要减掉front,是因为在逆置后半段的时候,front不再是0了,此时是n,如果不减去,那么mid=(m+2n-1)/2,将循环mid次,这时候就会越界。
}

总结:这是在一个数组中存放了2个数组([1,2,3,4,5,'|'6,7,8,9])这跟上一问的相同点是在同一个数组中进行操作,不同点是:第一问只操作一个数据(即转换的本身),而第二问操作的是一个数组中存放的2个“数组”,通过操作2个数组来间接操作一个数组。

problem3

设计一个尽可能高效的算法,将数组A[a0,a1,a2,a3,a4…an-1]循环左移p个位置,要求:1.给出设计思想2.实现3.给出实现的算法的时间、空间复杂度 示例:(X0,X1,X2,…Xn-1)=>(Xp,Xp+1,…,Xn-1,X0,…Xp-1).

//说实话,这题我一开始没看懂题目意思,题目的示例就没看太明白,不知道他怎么移动的。后面看到循环之后,结合答案给的具体例子,才看懂了。他是真的循环左移。循环在英语中是:circle,名词解释还有圆⭕圈的意思。
//如果给这个例子那可能就好理解了:
//1.abcdefgh=>循环左移3个位置=>defghabc 	注意下标为二、三的元素
//2.abcdefgh=>循环左移4个位置=>efghabcd	注意下标为三、四的元素
//3.abcdefgh=>循环左移5个位置=>fghabcde	注意下标为四、五的元素
//有找到规律吗?假设一个数组A要循环移动p个位置,那么就会是这样:A的前p个元素与后n-p个元素->n-p|p
//那不就是第二题的变形吗?即我这个p是随机的,而第二题的p是固定的。
//题外话:这让我想起了python的列表的data[-1]=data[7] 8(7-(-1))个元素,从0开始的逆序输出。

说了这么多,开始实现吧。

void Reverse(int A[],int front,int end){
    //解释一下形参:数组A,从front到end,循环移动front-end个位置
    int i,temp;
    int mid=(end-front+1)/2 //因为后面置换都用的是data[end],所以end=n-1,确保扫描数组的一半(n/2)
    for(i=0;i<mid;i++){
        temp =A[front+i];
        A[front+i]=A[end-i];
        A[end-i]=temp  //以上是置换的套路,写多了都记住怎么写了      
    }
}
void change(int A[],int n,int p){//形参传给调用的Reverse
    Reverse(A,0,n-1);//整体逆置 O(n/2)
     Reverse(A,0,p)//再逆置前p个元素(其实这个时候前p个已经在后n-p个后面了)O(p/2)
    Reverse(A,p,n-1);//再逆置后n-p个O((N-P)/2)
   
}
时间复杂度是O(n),空间复杂度是O(1)

总结:第三问与第二问相同点是:都是通过操作两个数组间接操作一个数据,不同点是:第二问操作的两个数组的长度都写死了,就是固定了哪两个,而第三问没有,他巧妙的通过循环移动p个位置这个变量,间接改变了数组的长度,但是本质没有发生变化。

总的来说:

1.这三道题,能总结的是:数组逆置都是相同的代码,就是Reverse()函数,变化的地方就是,操作一个数组还是通过间接操作两个数组来达到操作一个数组的目的。如果是操作一个数组,那么就是最简单的,也不会考。如果是通过操作2个数组间接操作一个数组,此时需要注意mid的编写(我的建议是直接写成(end-front+1)/2 确保能扫描任意一个数组的一半。

2.题目难度是递增的,不仅体现在真实难度上,更体现在对题意的理解上。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值