单链表一分为二
设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结点。
(这题可以在草稿纸上画画,感受一下结点是如何交换的)