数据结构-链表题(23.4.17)

173 阅读2分钟

单链表一分为二

设C={a1,b1,a2,b2,···,an,bn}为线性表,采用带头结点的单链表存放,设计一个就地算法,将其拆分成为两个线性表,使A={a1,a2,···,an},B={bn,···,b2,b1}。

代码

void divideAB(node *&c, node *&a, node *&b) {
    node *a_new = new node, *b_new = new node;
    a_new->next = NULL;
    b_new->next = NULL;
    node *c_old = c;
    node *s = c_old->next, *r = c_old;
    node *ra = a_new;
    node *sb = b_new->next;
    while (s != NULL) {
        r->next = s->next;
        ra->next = s;
        s->next = NULL;
        ra = s;
        s = r->next;
        r->next = s->next;
        s->next = sb;
        sb = s;
        b_new->next = s;
        s = r->next;
    }
    a = a_new;
    b = b_new;
}

题解

因为在线性表C中,属于数列A和B的元素个数相等,且A和B的元素在C中交替出现。所以在每轮循环中,结点s可以被操作两次。

本题的思路是创建两个新链表A和B,A用尾插法的方式创建,B用头插法的方式创建。因为每轮循环第一个结点一定属于A,第二个结点一定属于B,所以每轮循环先对当前结点使用尾插法插入到链表A中,再选择下一个结点,将该结点用头插法插入到B中。最终得到的A和B,链表A是顺序,链表B是逆序。

链表元素递增输出

给定一个带头结点的单链表,要求按递增次序输出单链表中各结点的数据元素(不借助数组作为辅助)。

代码

void display_sort(node *l) {
    node *s, *r;
    int i = 0, j = 0, n = length(l), tmp;//length()是之前写的函数之一,表示链表长度。
    while (i < n - 1) {
        s = l->next;
        r = s->next;
        j = 0;
        while (j < n - 1) {
            if ((s->data) > (r->data)) {
                tmp = s->data;
                s->data = r->data;
                r->data = tmp;
            }
            s = s->next;
            r = r->next;
            j++;
        }
        i++;
    }
}

题解

由于不允许使用数组作为辅助空间,这题主要是考察链表之间各个结点的交换。不同于数组的排序,这里需要注意结点的data与结点本身之间的关系,即交换的是结点。

(这里我使用的是冒泡排序的方法,时间复杂度比较高,有改进空间)

逆置单链表

将一个带头结点的单链表就地逆置(空间复杂度为O(1))

代码

node *reverse(node *l) {
    node *top = l, *p = l, *q = l->next;
    while (q != NULL) {
        p->next = q->next;
        q->next = top;
        top = q;
        p = l;
        q = l->next;
    }
    node *pre = top;
    while (pre->next != p) {
        pre = pre->next;
    }
    pre->next = q;
    node *tmp = new node;
    tmp->next = top;
    return tmp;
}

题解

这题要求就地逆置,就不能建立新的数组了,主要还是考察结点之间的交换。前面的循环中结点之间两两交换,最后新建一个头结点指向top结点。

(这题可以在草稿纸上画画,感受一下结点是如何交换的)