顺序表
1 两个有序表合并
//将两个有序的顺序表 A 和 B 合并为一个有序表 C
void MergeList(int *A, int *B, int *C, int ALen, int BLen, int CLen){
int i = 0, j = 0, k = 0;
// 依次比较 A 和 B 中元素的大小,依次放入 C 表,若有一表结束,另一表直接连接在 C 表末尾
while (i < ALen && j < BLen){
if (A[i] <= B[j])
C[k++] = A[i++];
else
C[k++] = B[j++];
}
//拼接剩余段
while (i < ALen) C[k++] = A[i++];
while (j < BLen) C[k++] = B[j++];
}
2 就地逆转
//将有序顺序表进行逆转
void Reverse(int *A, int Alen){
int mid = Alen/2;
for (int i = 0; i < mid; ++i) {
int temp = A[i];
A[i] = A[Alen - i - 1];
A[Alen - i - 1] = temp;
}
}
3 根据枢纽调整
//调整表 L,使左边元素均小于 temp,右边均大于等于 temp
void Adjust(int *L, int Llen, int temp){
int help[Llen];
int low = 0;
int high = Llen - 1;
for (int i = 0; i < Llen; ++i) //将 L 中的元素依次和 temp 比较
if (L[i] < temp)
help[low++] = L[i]; // L[i] < temp,从左向右存放
else
help[high--] = L[i]; // 反之从右至左存放
for (int j = 0; j < Llen; ++j) // 临时顺序表 help 中的元素依次复制到原表 L
L[j] = help[j];
}
4 顺序表主元素
//在一个顺序表中,元素值满足 0 <= ai < n(其中 n 为元素个数),规定若一个数出现的次数大于 n/2 ,则成为该顺序表的主元素
//[例] {5,1,2,5,5,1,6,2,5,5,5} 主元素为 5
int MainElement(int *A, int Len){
//因为元素值大小不会超过总元素个数 n,因此可以使用一个长度为 n 的数组来记录对应的数值均出现了几次
int *count = (int *)malloc(sizeof(int) * Len);
memset(count, 0, sizeof(int) * Len);
for (int i = 0; i < Len; ++i)
count[A[i]]++;
for (int j = 0; j < Len; ++j)
if (count[j] > (int)(Len/2))
return j;
else return -1;
}
5 循环左移元素
//将一个储存有 n (>1) 个元素的顺序表中的元素,循环左移 p 个单位
//[例] {1,2,3,4,5,6} 左移 3 位 {4,5,6,1,2,3}
void RotateLeft(int *A, int p, int Len){
int remove = p % Len; //remove 值就是新数组首元素在原数组中的下标
int *copy = (int *)malloc(sizeof(int) * Len); //将原数组复制一份
for (int i = 0; i < Len; ++i)
copy[i] = A[i];
//填入原数组后段元素
int count = 0;
for (int j = remove; j < Len; ++j)
A[count++] = copy[j];
//填入原数组前段元素
for (int k = 0; k < remove; ++k)
A[count++] = copy[k];
free(copy);
}
单链表
1 初始化
void InitLinkList(struct ListNode *L){
struct ListNode *ptr = L;
ptr->val = INT_MAX;
ptr->next = NULL;
}
2 头插法
void HeadCreatList(struct ListNode *L, int *elemt, int elemtSize){
for (int i = 0; i < elemtSize; ++i) {
struct ListNode *new = (struct ListNode *)malloc(sizeof(struct ListNode));
new->val = elemt[i];
new->next = L->next;
L->next = new;
}
}
3 尾插法
void TailCreatList(struct ListNode *L, int *elemt, int elemtSize){
for (int i = 0; i < elemtSize; ++i) {
struct ListNode *new = (struct ListNode *)malloc(sizeof(struct ListNode));
new->val = elemt[i];
new->next = NULL;
L->next = new;
L = L->next; //尾结点 L 后移
}
}
4 就地逆转
//就地逆转链表
void ReverseLinkList(struct ListNode *L){
//先将头结点摘下,然后剩余元素使用头插法插入
struct ListNode *ptr, *r;
ptr = L->next;
L->next = NULL; //摘下头结点
while (ptr){
r = ptr->next;
ptr->next = L->next;
L->next = ptr;
ptr = r;
}
}
5 按序输出
//按照递增次序输出带头结点的单链表中的数据元素,并释放节点所占用的空间,要求不使用额外的辅助数组
void PrintIncrease(struct ListNode *L){
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *pre = (struct ListNode *)malloc(sizeof(struct ListNode));
while (L->next != NULL){
cur = L->next;
pre = L->next;
int temp = INT_MAX; //temp 初值设置为最大
//工作指针 cur 依次对单链表元素进行遍历,temp 记录当前的最小值
//先找到当前链表元素中的最小值
while (cur->next != NULL){
cur = cur->next;
if (cur->val < temp)
temp = cur->val;
}
//如果只剩下最后一个结点,不用定位前驱,直接输出后,释放所有结点空间
if (L->next->next == NULL){
printf("%d", L->next->val);
struct ListNode *re = (struct ListNode *)malloc(sizeof(struct ListNode));
L->next = NULL;
free(re);
free(pre);
free(cur);
}
//找到最小值后,准备删除该结点,使用 pre 定位其前驱结点
while (pre->next->val != temp)
pre = pre->next;
//进行结点的输出与删除
printf("%d ", temp);
struct ListNode *s = (struct ListNode *)malloc(sizeof(struct ListNode));
s = pre->next;
pre->next = s->next;
free(s); //释放结点空间
}
}
6 删除特定结点
//在带头结点的单链表中,删除所有值为 data 的结点,并释放其空间,假设值为 data 的结点不唯一
void DeleteKeyNode(struct ListNode *L, int data){
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *pre = (struct ListNode *)malloc(sizeof(struct ListNode));
_Bool isChange = 0; //记录链表中是否还有值为 data 的结点
while (!isChange) { //根据 isChange 来决定是否继续删除
cur = L->next;
pre = L;
//查找是否还有值为 data 的结点
while (cur != NULL)
if (cur->val == data) {
isChange = 1;
break;
}else{
cur = cur->next;
}
//如果此时 isChange 仍旧为 0,说明已经不存在值为 data 的结点,删除结束
if (!isChange)
return;
//定位到删除结点的前驱
while (pre->next->val != data)
pre = pre->next;
struct ListNode *s = (struct ListNode *) malloc(sizeof(struct ListNode));
s = pre->next;
pre->next = s->next;
free(s);
//一次操作结束,isChange 归 0
isChange = 0;
}
}
7 单链表去重
//在一个递增有序的单链表中,有着相同的重复数值,删除链表中的重复数值
//[例] {7, 10, 10, 15, 18, 18, 19} {7, 10, 15, 18, 19}
void RemoveDuplicates(struct ListNode *L) {
struct ListNode *cur = (struct ListNode *) malloc(sizeof(struct ListNode));
struct ListNode *pre = (struct ListNode *) malloc(sizeof(struct ListNode));
//两个指针一前一后同时后移,若遇到两指针所指结点数值相同,删除后一个结点
//cur指向 cur->next,继续重复直至到达链表末尾
cur = L->next->next;
pre = L->next;
//只有一个结点
if (cur == NULL)
return;
while (cur) {
//两指针所指结点数值相同,需要删除
if (cur->val == pre->val) {
struct ListNode *dis = (struct ListNode *) malloc(sizeof(struct ListNode));
dis = cur;
cur = cur->next;
pre->next = cur;
free(dis);
} else {
cur = cur->next;
pre = pre->next;
}
}
}
8 删除介值元素
//在一个带头节点的单链表中所有数值无序存放,删除其中所有介于给定两值之间的元素
void DeleteInterValue(struct ListNode *L, int left, int right){
//将链表中的元素依次判定是否位于区间中,若符合,删除即可
struct ListNode *pre = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode));
pre = L;
cur = pre->next;
while (cur){
if (cur->val > left && cur->val < right){
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis = cur;
cur = cur->next;
pre->next = cur;
free(dis);
} else{
cur = cur->next;
pre = pre->next;
}
}
}
9 分解单链表
//将一个带头结点的单链表 A 分解为两个带头结点的单链表 B 和 C
//A中含有原表中序号为奇数的元素,B表中含有原表序号为偶数的元素
void SplitLinkList(struct ListNode *A, struct ListNode *B, struct ListNode *C){
struct ListNode *cur1 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *cur2 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *cur3 = (struct ListNode *)malloc(sizeof(struct ListNode));
cur1 = A->next;
cur2 = B;
cur3 = C;
int count = 1;
while (cur1){
struct ListNode *node = (struct ListNode *)malloc(sizeof(struct ListNode));
node->next = NULL;
node->val = cur1->val;
if (count % 2){ //奇数结点
cur2->next = node;
cur2 = cur2->next;
} else{ //偶数结点
cur3->next = node;
cur3 = cur3->next;
}
cur1 = cur1->next;
count++;
}
}
10 递增归并为递减
//将两个元素值递增排列的单链表 A 和 B,归并为一个按元素值递减排列的单链表,要求不使用额外的存储空间
struct ListNode* IncreaseAndDecrease(struct ListNode *A, struct ListNode *B){
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode)); //工作指针
struct ListNode *curA = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *curB = (struct ListNode *)malloc(sizeof(struct ListNode));
curA = A->next;
curB = B->next;
A->next = NULL; //将 A 的头结点摘下,用来存放最后合并的链表
while (curA && curB){ //两链表均不为空
if (curA->val <= curB->val){
cur = curA->next; //cur 记录 curA 的后继结点,防止断链
curA->next = A->next; //新节点头插法插入 A 链表
A->next = curA;
curA = cur; //工作指针 curA 后移
} else{
cur = curB->next; //记录 curB 的后继,防止断链
curB->next = A->next; //新节点头插法插入 A 链表
A->next = curB;
curB = cur; //工作指针 curB 后移
}
}
if (curA)
curB = curA;
while (curB){ //剩余结点继续使用头插法插入 A 链表
cur = curB->next;
curB->next = A->next;
A->next = curB;
curB = cur;
}
free(B);
}
11 公共元素建表
//A 和 B 是两个递增有序的带头结点的单链表,利用两者的公共元素产生单链表 C,要求不破坏 A、B 的结点
void PublicBuildList(struct ListNode *A, struct ListNode *B, struct ListNode *C, int ALen, int BLen){
//先求两表长,以短的为基准,依次将短链表的结点值与长链表比较,出现相等的值,建立新链表结点
//若短链表遍历结束,表示后续比较不可能出现相同元素,建表结束
struct ListNode *curTemp = (struct ListNode *)malloc(sizeof(struct ListNode)); //基准表的工作指针
struct ListNode *curOther = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *curRes = (struct ListNode *)malloc(sizeof(struct ListNode));
curRes = C;
if (ALen <= BLen){
curTemp = A->next;
curOther = B->next;
}else{
curTemp = B->next;
curOther = A->next;
}
while (curTemp && curOther){
//基准表数值小于比较表,基准表指针后移查看是否有相同元素
if (curTemp->val < curOther->val)
curTemp = curTemp->next;
//基准表数值大于比较表,说明比较表不可目前不可能存在和基准表相同的元素
//比较表指针后移,将下一个元素与基准表进行比较
else if(curTemp->val > curOther->val)
curOther = curOther->next;
else{ //两指针所指元素相同,建表,然后两指针同时后移
struct ListNode *res = (struct ListNode *)malloc(sizeof(struct ListNode));
res->val = curTemp->val;
res->next = NULL;
curRes->next = res;
curRes = curRes->next;
curTemp = curTemp->next;
curOther = curOther->next;
}
}
}
12 判断是否为子序列
//有两个序列已经存放于单链表 A 和 B 中,判断 B 是否为 A 的连续子序列
int IsSub(struct ListNode *A, struct ListNode *B, int ALen, int BLen){
struct ListNode *curOri = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *curSub = (struct ListNode *)malloc(sizeof(struct ListNode));
if (ALen <= BLen){ //取两者中长度较小者作为子序列
curOri = B->next;
curSub = A->next;
} else{
curOri = A->next;
curSub = B->next;
}
//将短的序列第一个结点值依次与长的结点值比较
while (curOri){
if (curSub->val != curOri->val){
curOri = curOri->next;
if (curOri == NULL) //较长者遍历结束,仍没有相等的结点,则不可能存在子序列
return 0;
} else{ //存在相等结点
while (curOri && curSub){
if (curSub->val == curOri->val){ //对应元素相等,两指针同时后移继续比较
curSub = curSub->next;
curOri = curOri->next;
if (curSub == NULL) //较短者遍历结束,是子序列
return 1;
}else //出现不同,说明非子序列
return 0;
}
}
}
}
13 删除绝对值相等结点
//一个链表包含 m 个结点,对于该链表中绝对值相等的结点,仅保留第一次出现的结点
//删除其余绝对值相等的结点,其中结点绝对值不会超过 n
//[例] 21 -> -15 -> -15 -> 8 -> 15 21 -> -15 -> 8
void RemoveAbsEqual(struct ListNode *L, int n){
struct ListNode *ptr = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
ptr = L;
int *help, m;
help = (int *)malloc(sizeof(int) * (n + 1));
//初始化辅助数组,标记全部置 0
for (int i = 0; i < n + 1; ++i)
*(help + i) = 0;
while (ptr->next){
//后方出现的绝对值相等的元素均设置为首先出现元素的相反数
m = ptr->next->val > 0 ? ptr->next->val : -ptr->next->val;
if (*(help + m) == 0){ //两数相加为 0,说明绝对值相同
*(help + m) = 1; //该数对应的标记置为 1,表示已经有该元素
ptr = ptr->next;
} else{
dis = ptr->next; //删除链表后方标记为 1 的多余元素
ptr->next = dis->next;
free(dis);
}
}
free(help);
}
14 求公共后缀
//求出两个单链表的公共后缀,返回公共后缀的起始地址
struct ListNode* PublicSuffix(struct ListNode *A, struct ListNode *B, int ALen, int BLen){
//两者中的较长者先走完两者的差值的路程,因为这段路程之内两者不可能指向同一地址
struct ListNode *curLong = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *curShort = (struct ListNode *)malloc(sizeof(struct ListNode));
if (ALen <= BLen){
curShort = A->next;
curLong = B->next;
} else{
curShort = B->next;
curLong = A->next;
}
//较长者先走完差值路程
int mid = abs(ALen - BLen);
while (mid){
curLong = curLong->next;
mid--;
}
//消除差值后,两者一起走,所指地址相同时即为公共后缀起始地址
while (curLong != curShort){
curLong = curLong->next;
curShort = curShort->next;
}
return curLong;
}
15 查找倒数第 k 结点
//假设一个链表只给出了头指针,不改变链表的前提下,查找链表中倒数第 K 个位置上的结点,返回该结点的值
int KthNodeFromTheBottom(struct ListNode *L, int k, int Len){
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode));
cur = L->next;
int mid = Len - k; //等价于查找正数第 length - k 个结点
while (mid){
cur = cur->next;
mid--;
}
return cur->val;
}
16 链表是否有环
//若一个链表有环,返回环的入口点
struct ListNode* isCircle(struct ListNode *L){
//快慢指针探测法,快指针步长为 2,慢指针步长为 1,若有环,则两个指针必定在某一时刻指向同一地址
struct ListNode *slow = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *fast = (struct ListNode *)malloc(sizeof(struct ListNode));
slow = L;
fast = L;
while (fast->next->next){
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
return slow;
}
//否则无环
return NULL;
}
17 重构单链表
//假设单链表带头结点,存储方式为 {a1, a2, ..., an},将其调整为 {a1, an, a2, an-1, ...}
void RefactorList(struct ListNode *L, int Len){
//将原链表中的元素分解,存储为两个顺序表,然后再依次重组成单链表
int *A = (int *)malloc(sizeof(int) * Len);
int *B = (int *)malloc(sizeof(int) * Len);
struct ListNode *res= (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode));
res = L;
//将原链表的头结点摘下
cur = L->next;
//原链表转化为顺序表
int cou = 0;
while (cur){
A[cou] = cur->val;
cou++;
cur = cur->next;
}
//顺序表中的元素相向遍历,存储进新的顺序表
int count = 0;
for (int i = 0, j = Len - 1; i <= j; ++i, --j) {
B[count++] = A[i];
B[count++] = A[j]; } //新的顺序表转链表
for (int k = 0; k < Len; ++k) {
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis->val = B[k];
dis->next = NULL;
res->next = dis;
res = res->next;
}
}
18 链表重排列
//已知带头结点的单链表 L,将该链表按结点数据域的值的大小从小到大重新链接
//要求链接过程中不得使用除链表以外的任何链结点空间
void insertsort(struct ListNode *L)
{//插入排序思想
struct ListNode *p,*q,*pre;
p = L->next->next;
L->next->next = NULL;
while(p)
{
q = p->next;
pre = L;
while(pre->next != NULL && pre->next->val < p->val)
pre = pre->next;
p->next = pre->next;
pre->next = p;
p = q;
}
}
19 删除最小结点
//在带头节点的单链表中删除(仅一个)最小值结点的高效算法
void DeleteMinElement(struct ListNode *L){
//cur工作指针,pre 始终指向最小值的前驱结点, temp 记录当前最小值
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *pre = (struct ListNode *)malloc(sizeof(struct ListNode));
cur = L->next;
pre = L;
int temp = INT_MAX;
//找到最小值结点
while (cur){
if (cur->val < temp)
temp = cur->val;
cur = cur->next;
}
//定位到最小值结点的前驱结点
while (pre->next->val != temp)
pre = pre->next;
//删除该结点
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis = pre->next;
pre->next = pre->next->next;
free(dis);
}
20 是否中心对称
//判断单链表 L 的前 n 个字符是否中心对称(是回文)
_Bool IsItSymmetrical(struct ListNode *L, int n){
//为便于比较,将链表前 n 个元素转为数组
int *list = (int *)malloc(sizeof(int) * n);
memset(list, 0, sizeof(int) * n);
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode));
cur = L->next;
int count = n;
while (count && cur){
list[n - count] = cur->val;
cur = cur->next;
count--;
}
//将数组中的元素相向比较,出现不同,则说明不是中心对称
for (int i = 0, j = n-1; i <= j; ++i, --j)
if (list[i] != list[j])
return 0;
return 1;
}
21 两链表的差集
//已知递增有序的单链表 A,B 分别存储一个集合,设计算法求出两个集合 A 和 B 的差集 A-B(即仅由在 A 中出现
//而不在 B 中出现的元素所构成的集合),并以同样的形式存储,同时返回该集合的元素个数
void SetDifference(struct ListNode *A, struct ListNode *B, struct ListNode *C){
struct ListNode *curA = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *curB = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *curC = (struct ListNode *)malloc(sizeof(struct ListNode));
curA = A->next;
curB = B->next;
curC = C;
while (curA && curB){ //A 、B两结点均不为空
if (curA->val < curB->val){
//A 小于 B,说明在 B 后序结点中不可能出现与 A 相同的值
//则该结点符合要求,构造链表,A 指针后移,B 不动
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis->val = curA->val;
dis->next = NULL;
curC->next = dis;
curC = curC->next;
curA = curA->next;
} else if (curA->val == curB->val){ //A值等于B值,不合要求,排除,两者的工作指针均后移
curA = curA->next;
curB = curB->next;
}else //A 值大于 B 值, B 的工作指针后移
curB = curB->next;
}
if (!curA) //模板链表当前元素为空,说明 A 中元素已经比较完,程序结束
return;
if (!curB){ //对照链表当前元素为空,说明 A 中剩余元素均符合,构造链表
while (curA){
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis->val = curA->val;
dis->next = NULL;
curC->next = dis;
curC = curC->next;
curA = curA->next;
}
}
}
22 特殊要求链表1
//已知一个单链表中每个结点存放一个整数,并且结点数不少于 2,请设计算法以判断该链表中第二项
//起的每个元素值是否等于其序号的平方减去其前驱的值,若满足则返回 ture,否则返回 false
_Bool SpecialLinkedList_01(struct ListNode *L){
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *pre = (struct ListNode *)malloc(sizeof(struct ListNode));
pre = L->next;
cur = L->next->next;
int index = 2;
while (cur){
if (cur->val == (index * index - pre->val)){
cur = cur->next;
pre = pre->next;
index++;
} else return 0;
}
return 1;
}
23 特殊要求链表2
//设有一个由正整数组成的无序单链表,编写完成下列功能的算法:
//(1)找出最小值结点,且打印该数值
//(2)若该数值是奇数,则将其与直接后继结点的数值交换
//(3)若该数值是偶数,则将其直接后继结点删除
void SpecialLinkedList_02(struct ListNode *L){
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *pre = (struct ListNode *)malloc(sizeof(struct ListNode));
pre = L->next;
cur = L->next;
int temp = INT_MAX;
//找到最小值
while (cur){
if (cur->val < temp)
temp = cur->val;
cur = cur->next;
}
printf("Min Node: %d\n", temp);
//定位到最小值结点
while (pre->val != temp)
pre = pre->next;
//数值为奇数,交换数值
if (temp % 2){
if (pre->next){
int te = pre->val;
pre->val = pre->next->val;
pre->next->val = te;
}
} else{ //数值为偶数,删除后继
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis = pre->next;
pre->next = pre->next->next;
free(dis);
}
}
24 特殊要求链表3
//设有一个正整数序列组成的有序单链表(按递增次序有序,且允许有相等的整数存在),编写实现下列功能的算法:
//(1)确定在序列中比正整数 x 大的数有几个(相同的数只计算一次,如序列
// {4,5,7,7,8,10,11,15,15,16,17,20,20}中比 10 大的数有 5 个)
//(2)在单链表中将比正整数 x 小的数按递减次序排列
//(3)将比正整数 x 大的偶数从单链表中删除
void SpecialLinkedList_03(struct ListNode *L, int Len, int x){
struct ListNode *cur = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *res = (struct ListNode *)malloc(sizeof(struct ListNode));
res = L; //摘下头结点
cur = L->next; //工作指针
//链表转顺序表
int *list = (int *)malloc(sizeof(int ) * Len);
memset(list, 0, sizeof(int) * Len);
int count = 0; //比 x 小的数字个数
int index = 0; //数组下标
int left = -1; //记录较小数的末尾下标
int right = Len; //记录较大数的起始下标
while (cur){
list[index] = cur->val;
if (cur->val < x){ //当前元素小于 x
left++;
if (cur->val != cur->next->val) //且不重复
count++;
}
if (cur->val > x)
right--;
index++;
cur = cur->next;
}
printf("The count of small than x: %d\n", count);
//将比 x 小的数按照递减顺序排列,即反转当前的小元素表
for(int i = 0, j = left; i <= j; ++i, --j){
int temp = list[i];
list[i] = list[j];
list[j] = temp;
}
//将比 x 大的数中偶数删除
int oddInd = 0; //奇数数组的索引
int *odd = (int *)malloc(sizeof(int ) * (Len - right));
memset(odd, 0, sizeof(int) * (Len - right));
//大于 x 的奇数存进新的表中,等于删除了偶数
for (int k = right; k < Len; ++k)
if (list[k] % 2)
odd[oddInd++] = list[k];
//最终结果生成链表
for (int l = 0; l < right; ++l) {//链接原链表中小于等于 x 的元素
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis->val = list[l];
dis->next = NULL;
res->next = dis;
res = res->next;
}
for (int m = right, n = 0; m < Len, n < oddInd; ++m, ++n) { //链接原链表中大于 x 的元素
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis->val = odd[n];
dis->next = NULL;
res->next = dis;
res = res->next;
}
}
25 特殊要求链表4
//已知三个带头结点的线性链表 A、B 和 C 中的结点均依元素值自小至大排列,编写算法对 A 表进行如下操作:
//使操作后的链表 A 中仅留下三个表中均包含的数据元素的结点,且没有值相同的结点,并释放所有无用结点
// 限定算法的时间复杂度为 O(m+n+p),其中 m、n和 p 分别为三个表的长度
//公共元素建表,结果保留在第一个链表中
void BulidListPublic(struct ListNode *L1, struct ListNode *L2){
struct ListNode *cur1 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *cur2 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *pre = (struct ListNode *)malloc(sizeof(struct ListNode));
pre = L1; //始终指向 cur1 的前驱结点
cur1 = L1->next;
cur2 = L2->next;
while (cur1 && cur2){
//当前 L1 元素小于 L2,则说明当前元素不可能是两者公共元素,cur1 后移,cur2 不动,删除该结点
if (cur1->val < cur2->val){
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis = cur1;
pre->next = cur1->next;
cur1 = cur1->next;
pre = pre->next;
free(dis);
}else if (cur1->val > cur2->val){ //当前 L1 元素大于 L2,cur1 不动,cur2 后移
cur2 = cur2->next;
} else{ //两者当前元素相同,保留该结点,工作指针同时后移
cur1 = cur1->next;
cur2 = cur2->next;
}
}
//L1 和 L2 只要有一个遍历结束,则没有结束的链表中所有元素均不可能成为公共元素,全部删除
if (cur1){
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis = cur1;
pre->next = cur1->next;
cur1 = cur1->next;
free(dis);
}
}
void SpecialLinkedList_04(struct ListNode *A, struct ListNode *B, struct ListNode *C){
//先求 A 和 B 的交集,改变 A 链表
BulidListPublic(A, B);
//再求 A 和 C 的交集,改变 A 链表
BulidListPublic(A, C);
}
26 特殊要求链表5
//已知两个单链表 A 和 B,其头指针分别为 heada 和 headb,编写一个过程从单链表 A 中删除自第 i 个元
//素起的共 len 个元素,然后将单链表 A 插入到单链表 B 的第 j 个元素之前
void SpecialLinkedList_05(struct ListNode *A, struct ListNode *B, int start, int len, int insert){
struct ListNode *cur1 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *cur2 = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *pre = (struct ListNode *)malloc(sizeof(struct ListNode));
int startIndex = 1; //指示 A 链表中删除的起始位置
int removeCount = 0; //指示 A 中删除元素的长度
int insertIndex = 1; //指示 B 中插入元素的位置
cur1 = A->next;
cur2 = B->next;
pre = A;
while (cur1){
while (startIndex != start){//定位到删除位置
cur1 = cur1->next;
pre = pre->next;
startIndex++;
}
while (removeCount != len){//开始删除
struct ListNode *dis = (struct ListNode *)malloc(sizeof(struct ListNode));
dis = cur1;
pre->next = cur1->next;
cur1 = cur1->next;
free(dis);
removeCount++;
}
break;
}
while (cur1->next) //删除后为方便接下来的插入连接操作,将 cur1 移动到 A 的末尾元素
cur1 = cur1->next;
while (cur2){
while (insertIndex != (insert - 1)){ //定位到插入位置的前驱
cur2 = cur2->next;
insertIndex++;
}
break;
}
//插入 A 链表
struct ListNode *r = (struct ListNode *)malloc(sizeof(struct ListNode));
r = cur2->next;
cur2->next = A->next;
cur1->next = r;
}
27 交换结点
//编写一个算法来交换单链表中指针 P 所指结点与其后继结点,HEAD 是该链表的头指针,P 指向该链表中某一结点
void ExchangeNode(struct ListNode *L, struct ListNode *p){
struct ListNode *pre = (struct ListNode *)malloc(sizeof(struct ListNode));
struct ListNode *post = (struct ListNode *)malloc(sizeof(struct ListNode));
pre = L;
post = p->next->next; //记录 p 的后继的后继,防止断链
while (pre->next != p) //定位到 p 的前驱
pre = pre->next;
pre->next = p->next;
p->next->next = p;
p->next = post;
}
单循环链表
1 尾插法建立
//尾插法建立循环链表
void CreatCirList(struct ListNode *L, int *list, int len){
struct ListNode *tail, *head;
L->next = NULL;
head = L;
for (int i = 0; i < len; ++i) {
struct ListNode *new = (struct ListNode *)malloc(sizeof(struct ListNode));
new->val = list[i];
L->next = new;
L = new;
}
tail = L; //将尾结点赋值给尾指针
tail->next = head->next; //将尾指针的指针域指向第一个元素
}
2 删除指定结点前驱
//在一循环单链表中,既无头结点也无头指针.s 为指向某个结点的指针,删除 s 所指结点的前驱结点
void RemoveNodePre(struct ListNode *L, struct ListNode *s){
struct ListNode *pre;
pre = s;
//找到待删除结点的前驱
while (pre->next->next != s)
pre = pre->next;
//删除结点
struct ListNode *dis = pre->next;
pre->next = s;
free(dis);
}
3 连接两循环单链表
//假设有两个循环单链表 A 和 B,头指针分别为 hradA 和 headB,将 B 连接到 A 之后,要求连接后仍是循环链表
void MergeCirList(struct ListNode *A, struct ListNode *B, int ALen, int BLen){
struct ListNode *tailA = A;
struct ListNode *tailB = B;
//分别定位到 A 和 B 的尾结点
while (ALen){
tailA = tailA->next;
ALen--;
}
while (BLen){
tailB = tailB->next;
BLen--;
}
//连接两链表
tailA->next = B->next; //A 的尾结点下一节点为 B 的第一个结点
tailB->next = A->next; //B 的尾结点下一节点为 A 的第一个结点
}
4 循环删除最小值
//一个带头结点的循环链表中的值均为正,反复找出链表中的最小值结点并删除,直至链表为空,最后删除头结点
void RemoveMinCirList(struct ListNode *L, int Len){
struct ListNode *cur, *curPre, *min, *minPre;
min = L->next;
minPre = L;
int temp = Len;
while (Len){ //表不为空时进行循环
cur = L->next; //工作指针
curPre = L; //始终指向工作指针前驱
while (temp){ //单次循环找最小值
if (cur->val < min->val){
min = cur;
minPre = curPre;
}
curPre = cur; //两个工作指针同时后移
cur = cur->next;
temp--;
}
struct ListNode *dis = min;
min = min->next;
minPre = minPre->next;
printf("Remove Node %d\n", dis->val);
free(dis); //删除结点空间
Len--;
}
//释放头结点
free(L);
printf("Remove Head Node");
}
双向链表
1 尾插法建立
void CreatDulList(struct DulListNode *L, int *list, int Len){
struct DulListNode *tail;
L->prior = NULL;
L->next = NULL;
tail = L; //tail 始终指向尾结点
for (int i = 0; i < Len; ++i) {
struct DulListNode *new = (struct DulListNode *)malloc(sizeof(struct DulListNode));
new->val = list[i];
tail->next = new;
new->prior = tail;
tail = new;
}
tail->next = NULL;
}
2 插入结点
//在双链表的位置 index 之后插入一个新节点 element
void InsertDulList(struct DulListNode *L, int index, int element){
struct DulListNode *cur = L->next;
//定位到插入位置之前的结点
while (index - 1){
cur = cur->next;
index--;
}
//插入新结点
struct DulListNode *new = (struct DulListNode *)malloc(sizeof(struct DulListNode));
new->val = element;
new->next = cur->next;
cur->next->prior = new;
new->prior = cur;
cur->next = new;
}
3 删除结点
//删除双链表第 index 位置的元素
void RemoveDulNode(struct DulListNode *L, int index){
struct DulListNode *cur = L->next;
struct DulListNode *pre = L; //始终指向被删除结点的前驱
//定位到被删节点
while (index - 1){
cur = cur->next;
pre = pre->next;
index--;
}
struct DulListNode *dis = cur;
pre->next = cur->next;
cur->next->prior = pre;
free(dis);
}