剑指offer 调整数组顺序使奇数位于偶数前面

题目描述:
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

思路:
其实这道题我的第一想法就是利用归并排序的思想来实现,但是这样的话时间复杂度会是O(nlogn),空间复杂度是O(n),不可取。

既然是移动操作,在数组上必然很费时间,因此我想到了用双向链表来实现,这样的话时间复杂度是O(n),空间复杂度是O(1),可以。

具体实现:

首先遍历链表,将所有奇数的节点插入到第一个偶数节点之前,这样遍历完成后一定满足题意。但是写完提交上去后返回TLE,这令我不得其解,难道链表的效率还不如数组?感觉因该是插入操作写搓了,死循环导致,出了几组样例,果然发现了其中的问题,1 1 0这组数据,按照我的思路,第一个1会插入到0的前面,然后是第二个1,此时第一个1已经跑到第二个1的后面,插入完第二个1,又回到了原来状态,这样会死循环,因此我们一定要从第一个偶数节点的后面遍历,而不是从头遍历,这样问题就解决了。

#include <cstdio>
using namespace std;

typedef struct Node{
    int val;
    Node *pre;
    Node *next;
    Node(int val = -1) : val(val), pre(NULL), next(NULL){}
} *pNode;

class List{
private:
    pNode Head;//头指针
    pNode Tail;//尾指针
    pNode First_Even;//第一个偶数节点指针
    pNode First_Odd;//第一个奇数节点指针
    void Insert_Node(pNode);//插入一个节点在第一个偶数节点之前
    void Traverse_List(pNode);
    void Reverse_Travese_List(pNode);
    void Delete_List(pNode);//删除链表
    bool is_Odd(pNode);
public:
    void Insert_Node(int);//在尾部添加节点
    void Traverse_List();//遍历链表
    void Reverse_Travese_List();//反向遍历链表
    void Algorithm();//满足题目算法的具体实现
    List();
    ~List();
};

void List::Insert_Node(int x){
    pNode node = new Node(x);
    if(this->First_Even == NULL && !is_Odd(node))//指向第一个偶数节点的地址
        this->First_Even = node;
    if(this->First_Odd == NULL && this->First_Even != NULL && is_Odd(node))
        this->First_Odd = node;//注意这里一定要加上 this->First_Even != NULL 这句!!
    this->Tail->next = node;
    node->pre = this->Tail;
    this->Tail = node;
}

void List::Insert_Node(pNode node){
    if(node == this->Tail)
        this->Tail = node->pre;
    node->pre->next = node->next;
    if(node->next != NULL)
        node->next->pre = node->pre;
    node->next = this->First_Even;
    node->pre = this->First_Even->pre;
    this->First_Even->pre->next = node;
    this->First_Even->pre = node;
}

void List::Algorithm(){
    if(this->First_Even == NULL || this->First_Odd == NULL)
        return;//只存在一种数字,则直接输出
    pNode p = this->First_Odd;
    pNode psave = NULL;
    while(p){
        psave = p->next;
        if(is_Odd(p)){
            Insert_Node(p);//遍历链表寻找所有奇数节点插入到第一个偶数节点之前
        }
        p = psave;
    }
}

void List::Reverse_Travese_List(){
    Reverse_Travese_List(this->Tail);
}

void List::Reverse_Travese_List(pNode node){
    if(node != this->Head){
        printf("%d ", node->val);
        Reverse_Travese_List(node->pre);
    }
}

void List::Traverse_List(){
    Traverse_List(this->Head->next);
}

void List::Traverse_List(pNode node){
    if(node){
        printf("%d", node->val);
        if(node != this->Tail)
            printf(" ");
        Traverse_List(node->next);
    }
}

bool List::is_Odd(pNode node){
    int x = node->val > 0 ? node->val : -node->val;
    return x % 2 == 1;
}

void List::Delete_List(pNode node){
    if(node){
        Delete_List(node->next);
        delete node;
    }
}

List::List(){
    this->Head = new Node();//表头结点,不参与计算
    this->Tail = this->Head;
    this->First_Even = NULL;
    this->First_Odd = NULL;
}

List::~List(){
    Delete_List(this->Head);
}

int main()
{
    List *list = new List;
    int n;
    scanf("%d", &n);
    while(n--){
        int x;
        scanf("%d", &x);
        list->Insert_Node(x);
    }
    list->Algorithm();
    list->Traverse_List();
    printf("\n");
    // list->Reverse_Travese_List();
    // printf("\n");
    delete list;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值