线性表相关
单链表的原地逆置(带头结点)
思想:将头结点摘下,然后从第一个结点开始,依次前插到头结点后面(其实就相当于前插法创建链表)
LinkList Reverse(LinkList L)
{
LinkList p;
p = L->next; //找到首结点
L->next = NULL; //摘下头结点
while (p != NULL)
{
p->next = L->next;
L->next = p;
}
return L;
}
顺序表的原地逆置
思想:第一个元素和最后一个元素对调,第一二个元素和倒数第二个元素对调,...,依此类推。
void Reverse(SqList &L)
{
int n =L.length;
int,temp;
for(i=0,i<n/2;i++)
{
temp=L.data[i];
L.data[i]=L.data[n-i-1];
L.data[n-i-1]=temp;
}
}
应用:将数组R中某序列左移p个位置
思路:先将[0,p-1]逆置,再将[p,n-1]逆置,最后整个数组逆置。
从尾到头反向输出链表元素(带头结点)
方法1:先原地逆置,再输出
方法2:正向读取依次放到栈中,然后输出栈中元素
方法3:利用递归,每当访问一个结点时i,先递归输出它后面的结点,再输出它自己。(如下)
void Reverse(LinkList L)
{
if (L->next != NULL)
Reverse(L->next);
cout << L->data;
}
两个有序顺序表合并成一个新的有序顺序表
思想:首先,按顺序不断取下两个顺序表表头较小的结点存入新的顺序表中。然后,看哪个表还有剩余,将剩下的部分加到新的顺序表后面。
bool Merge(SqList A, SqList B, SqList &C)
{
int lenA = A.length, lenB = B.length;
if (lenA + lenB > C.maxSize)
return false;
int i = 0, j = 0, k = 0;
while (i < lenA && j < lenB)
{
if (A.data[i] <= B.data[j])
C.data[k++] = A.data[i++];
else
C.data[k++] = B.data[j++];
}
while (i < lenA)
C.data[k++] = A.data[i++];
while (j < lenB)
C.data[k++] = A.data[j++];
C.length = k;
return true;
}
非常典型。
两个递增的链表合并成一个递减的链表。(不采用第三个链表)
思想:均从第一个结点进行比较,将较小的结点链入链表,同时后移工作指针后移。另外,用头插法来解决总链表递减的问题。
void Merge(LinkList &La, LinkList &Lb)
{
LinkList r, pa = La->next, pb = Lb->next;
La->next = NULL; // 为了头插,将头结点取下
while (pa && pb)
{
if (pa->data <= pb->data)
{
r = pa->next;
pa->next = La->next;
La->next = pa;
pa = r;
}
else
{
r = pb->next;
pb->next = La->next;
La->next = pb;
pb = r; // 工作指针后移,但不能用pa=pa->next,因为pa->next已被占用
}
}
if (pa)
pb = pa;
while (pb)
{
r = pb->next;
pb->next = La->next;
La->next = pb;
pb = r;
}
free(Lb);
}
两个有序链表的有序合并(合并到第三个链表中)
LinkList Merge(LinkList L1, LinkList L2)
{
LinkList L = NULL;
if (L1 == NULL)
return L2;
else if (L2 == NULL)
return L1;
else
{
if (L1->data < L2->data)
{
L = L1;
L->next = Merge(L1->next, L2);
}
else
{
L = L2;
L->next = Merge(L1, L2->next);
}
return L;
}
}
两个链表的拼接
void Merge2(LinkList L1, LinkList L2)
{
LinkList p;
for (p = L1; p->next != NULL; p = p->next);
p->next = L2->next; // 与第二个链表的首结点连上,而不是头结点
free(L2); // 释放第二个链表的头结点
}
将循环单链表L2连接到循环单链表L1后面,使仍保持循环
思想:先找到两个链表的尾指针,将第一个链表的尾指针与第二个链表的头结点连接起来,再使之成为循环的。
LinkList Link(LinkList &L1, LinkList &L2)
{
LinkList p, q;
p = L1;
while (p->next != L1)
p = p->next;
q = L2;
while (q->next != L2)
q = q->next;
p->next = L2;
q->next = L1;
return L1
}
判单循环双链表是否对称
思想:从两头往中间扫描
bool Symmetry(LinkList L)
{
LinkList p = L->next, q = L->prior;
while (p != q && p->next != q) //总长度为奇或偶两种情况
{
if (p->data == q->data)
{
p = p->next;
q = q->prior;
}
else
return false;
}
return true;
}
删除顺序表中所有值为x的元素。要求时空复杂度为O(n)、O(1)
void Del_x(SqList &L, int x)
{
int i, k = 0;
for (i = 0; i < L.length; i++)
{
if (L.data[i] != x) // 如果换成【L.data[i]<S || L.data[i]>T】,就是【删除值介于S与T之间的元素】
{
L.data[k] = L.data[i];
k++;
}
}
L.length = k; // 这一句很重要
}
递归删除单链表中所有值为x的结点(不带头结点)
void Del(LinkList &L, int x)
{
LinkList q; // q指向待删除结点,当替罪羊
if (L == NULL)
return;
if (L->data == x)
{
q = L;
L = L->next;
free(q);
Del(L, x);
}
else
Del(L->next, x);
}
删除单链表中所有值为x的结点(带头结点)
思想:用p从头到尾扫描, pre是其前前驱。若p所指向的值为x, 则删除,并让p移向下一个节点;否则让p和pre同步后移一个节点。
void DelX(LinkList &L, int x)
{
LinkList pre = L, p = L->next, q; //想要删除p结点,就要知道它的前驱,故pre结点不能省略 。q当替罪羊
while (p != NULL)
{
if (p->data == x) //如果修改为【if(p->data>low && p->data<high)】,则该函数的功能就是【删除值介于low和high之间的所有节点】
{
q = p; // q指向待删除结点(替罪羊)
p = p->next;
pre->next = p;
free(q);
}
// 也能这样写,因为待删除结点和其前驱都是已知的前驱
// if(p->data==x)
// {
// pre->next=p->next;
// free(p);
// p=pre->next;
// }
else
{
pre = p;
p = p->next;
}
}
}
删除单链表中的唯一最小值结点(带头结点)
void DelMin(LinkList &L)
{
LinkList pre = L, p = L->next;
LinkList minpre = pre, minp = p;
while (p != NULL)
{
if (p->data < minp->data)
{
minp = p;
minpre = pre;
}
pre = p;
p = p->next;
}
minpre->next = minp->next;
free(minp);
}
删除单链表绝对值相同的数
思想:设置一个数组,用于判断是否出现过绝对值相同的元素,将出现过的元素在数组对应位置中标记为1,如果之后的元素在数组中等于1,说明之前出现过相等的绝对值,将他删除
void del_same(LinkList &L, int n)
{
int m;
int *q = new int[n + 1];
LNode *p = L, *r;
for (int i = 0; i < n + 1; i++)
q[i] = 0;
while (p->next != NULL)
{
m = p->next->data > 0 ? p->next->data : -p->next->data;
if (q[m] == 0)
{
q[m] = 1;
p = p->next;
}
else
{
r = p->next;
p->next = r->next;
free(r);
}
delete q;
}
}
有序表中删除所有值重复的元素,要求时空复杂度为O(n),O(1)
void Del_Same(SqList L)
{
int len = L.length;
int i, k = 1;
for (i = 1; i < len; i++)
{
if (L.data[i] != L.data[i - 1])
L.data[k++] = L.data[i];
}
L.length = k; // 不能省略,因为k之后还有其他元素,但不是想要的
}
(如果改成无序表,则要用散列表才能达到时间复杂度O(n))
按递增序列输出单链表中各节点数据元素,并删除此元素(带头结点)
思想:遍历一次找到一个最小结点,输出并删除,以此类推遍历n次,每次都找到最小结点输出并删除。
void del_min(LinkList L)
{
LinkList minpre = L, p = L->next, q;
while (L->next != NULL)
{
while (p->next != NULL)
{
if (p->next->data < minpre->next->data)
minpre = p;
p = p->next;
}
cout << minpre->next->data;
q = minpre->next;
minpre->next = q->next;
free(q);
minpre = L;
p = L->next;
}
free(L);
}
用高效算法输出单链表中倒数第k个值
思想:设置两个指针pq,均指向第一个节点。p向后移动,当移动到第k个结点时,两个指针开始同时后移,当p到末尾时,q恰好在第k个结点上。
int Search_k(LinkList &L, int k)
{
LNode *p = L->next, *q = L->next;
int i = 1;
while (i < k)
{
p = p->next;
i++;
}
if (p == NULL)
return 0;
while (p->next != NULL)
{
p = p->next;
q = q->next;
}
cout << q->data << endl;
return 1;
}
将链表A分成链表A和B,分别含有奇位元素和偶位元素
思想:为保持相对顺序不变,采用尾插法。
void Split(LinkList &A)
{
int i = 0;
LinkList B, p;
B = (LinkList)malloc(sizeof(LNode));
B->next = NULL;
LinkList ra = A, rb = B;
p = A->next;
A->next = NULL;
while (p != NULL)
{
i++;
if (i % 2 == 0)
{
rb->next = p;
rb = p;
}
else
{
ra->next = p;
ra = p;
}
p = p->next;
}
ra->next = rb->next = NULL;
}
判断链表B是否为链表A的连续子序列
算法思想:因为两个整数序列已存入两个链表中,操作从两个链表的第一个结点开始,若对应数据相等,则后移指针;若对应数据不相等,则A链表从上次开始比较结点的后继开始,B链表仍从第一个结点开始比较,直到B链表到尾表示匹配成功。A链表到尾而B链表未到尾表示失败。操作中应记住A链表每次的开始节点,以便下次匹配时好从其后继开始。
int Pattern(LinkList A, LinkList B)
{
LinkList p = A;
LinkList pre = p;
LinkList q = B;
while (p && q)
{
if (p->data == q->data)
{
p = p->next;
q = q->next;
}
else
{
pre = pre->next; // 主串从上次开始比较的结点的后继开始
p = pre;
q = B; // 子串从头开始
}
}
if (q == NULL)
return 1;
else
return 0;
}
在递增的单链表中,使重复的值只保留一个
思想:既然是递增,那么重复的值一定是相邻的。用p扫描链表L,若 *p的值等于它后继结点的值,则删除它的后继结点,否则p移向下一个结点
void DelSame(LinkList &L)
{
LinkList p = L->next, q;
if (p == NULL)
return;
while (p->next != NULL)
{
q = p->next;
if (p->data == q->data)
{
p->next = q->next;
free(q);
}
else
p = p->next;
}
}