目录
链表的合并
链表的结点逆置
顺序表的高效划分
链表的合并
已知两个递增有序的单链表A和B,分别表示两个集合。试设计一个算法,用于求出A与B的交集,并存储在C链表中。例如 : La = {2,4,6,8};Lb = {4,6,8,10};Lc = {4,6,8}。(要求上机实现完整程序代码、核心代码有注释,有运行结果)。
算法分析:遍历这两个链表A和B,使用两个指针,创建一个新的空链表C,然后比较当前节点的数据,如果相等,则将该数据添加到链表C中,然后同时移动两个链表的指针。如果不相等,则移动较小值所在链表的指针。这样可以确保只添加两个链表中共有的元素到链表C中。
#include <stdio.h>
#include <malloc.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next; //指向后继结点
} LinkNode;
//创建单链表,头插法
LinkNode * createlist(int a[],int len) {
//len是链表的长度
LinkNode * L;
LinkNode * s;
L = (LinkNode *)malloc(sizeof(LinkNode));
L -> next = NULL;//创建头结点,next指向为空
for(int i = 0; i < len; i++) {
s = (LinkNode*)malloc(sizeof(LinkNode));//创建结点s
s -> data = a[i];
s -> next = L -> next; //将s插入原首节点前,头结点后
L -> next = s;
}
return L;
}
//用于打印链表
//由于存储链表使用的是头插法,所以打印时我们现将链表存入一个数组
//再将那个数组反向输出就是我们需要的样子
void printlist(LinkNode *L) {
LinkNode *p = L -> next;//让p指向首结点
int arr[4];
int len = 0,i = 0;
while(p != NULL) {
arr[i] = p -> data;
p = p -> next;
i++,len++;
//只要没到尾结点就一直存入arr数组
}
len = len - 1;//最后多加了一次len所以要减去
for(int i = len; i >= 0; i--) {
printf("%d ",arr[i]);
}
printf("\n");
}
//求两个链表的交集
LinkNode * intersection(LinkNode *a,LinkNode *b) {
//传入a,b两个链表
LinkNode *c;
c = (LinkNode *)malloc(sizeof(LinkNode));
LinkNode *r = c;
//创建链表c的头结点,使用尾插法
a = a -> next,b = b -> next;
//让链表a和链表b指向它们的首结点
LinkNode *p;
while(a != NULL && b != NULL) {
if(a -> data == b -> data) {
//若二值相等,使用尾插法存入c中,并且让这两个指针都往后移动
p = (LinkNode *)malloc(sizeof(LinkNode));
p -> data = a -> data;
r -> next = p;
r = r -> next;
a = a -> next,b = b -> next;
}
else {
//由于创建列表时使用了尾插法,所以要变得相反
//若二值不相等则值更大的往后移一格
if(a -> data > b -> data)
a = a -> next;
if(b -> next > a -> next)
b = b -> next;
}
}
r -> next = NULL;
//尾插法注意要让尾结点的next域置为空
return c;
}
int main() {
//创建链表a
int a[4];
a[0] = 2,a[1] = 4,a[2] = 6,a[3] = 8;
LinkNode *la;
la = createlist(a,4);
printf("链表a为:");
printlist(la);
//创建链表b
int b[4];
b[0] = 4,b[1] = 6,b[2] = 8,b[3] = 10;
LinkNode *lb;
lb = createlist(b,4);
printf("链表b为:");
printlist(lb);
//得到链表la和lb的交集lc
LinkNode *lc = intersection(la,lb);
printf("链表a和链表b的交集链表c为:");
printlist(lc);
}
链表的结点逆置
假设有一个带头结点的单链表L=(2,4,6…,20)。设计一个算法将所有结点逆置,即:L=(20,18,…,2)。(要求要求上机实现完整程序代码、核心代码有注释,有运行结果)
算法分析:可以使用尾插法建立第一个链表,再写一个逆置函数,传入这个链表,在函数里面改变当前节点的指针使其指向其前一个节点,以此类推,直到遍历完所有的节点。
#include <stdio.h>
#include <malloc.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next; //指向后继结点
} LinkNode;
//创建单链表,尾插法
LinkNode * createlist(int a[],int len) {
LinkNode *L,*r,*s;
L = (LinkNode*)malloc(sizeof(LinkNode));
//L为头结点
r = L;
for(int i = 0; i < len; i++) {
s = (LinkNode *)malloc(sizeof(LinkNode));
s -> data = a[i];
r -> next = s;
r = r -> next;
//将数据存入s中并且让r的next指向它
//再将r向后移动一格
}
r -> next = NULL;
//记得要让尾结点的next域为空
return L;
}
//打印单链表
void printlist(LinkNode * l) {
l = l -> next;
//让l指向它的首结点
while(l != NULL) {
printf("%d ",l -> data);
l = l -> next;
}
printf("\n");
}
//打印逆置后的单链表
void printreverselist(LinkNode *l) {
//采用这种逆置方法后不用指向首结点,此时l即为首结点
while(l != NULL) {
printf("%d ",l -> data);
l = l -> next;
}
printf("\n");
}
//逆置链表函数
LinkNode * reverselist(LinkNode * head) {
//创建新的头结点p
LinkNode *p;
LinkNode *l,*r;
l = head -> next;
//l表示left,是左边的指针
//r表示right,是右边的指针
//让s指向首结点,头结点的next指向空
head -> next = NULL;
//核心代码
while(l != NULL) {
r = l -> next;//保存当前节点的下一个节点
l -> next = p;//将当前节点的next指向前一个节点
p = l;//更新p为当前节点
l = r;//移动到下一个节点
}
return p;
}
int main() {
//创建逆置前的链表
int a[100];
int n = 1;
for(int i = 0; i < 10; i++) {
a[i] = 2 * n;
n++;
}
LinkNode *l = createlist(a,10);
printf("逆置前的链表为:");
printlist(l);
//逆置链表
l = reverselist(l);
printf("逆置后的链表为:");
printreverselist(l);
}
顺序表的高效划分
对有n个整形元素的顺序表以第一个元素为基准进行高效划分,将所有大于该基准的所有元素放在该基准的右边;将所有小于等于该基准的所有元素放在该基准的左边。例如对于线性表(17,2,3,5,4,20,1,18,19,20,21,6,22)要求要求上机实现完整程序代码、核心代码有注释,有运行结果)
#include <stdio.h>
#include <malloc.h>
#define MaxSize 50
typedef int ElemType;
typedef struct
{ int data[MaxSize]; //存放顺序表元素
int length; //存放顺序表的长度
} SqList; //顺序表的类型
//建立顺序表
SqList * createlist(int a[],int len) {
SqList *l;
l = (SqList *)malloc(sizeof(SqList));
int k = 0;
//k用于记录顺序表的长度
for(int i = 0; i < len; i++) {
l -> data[i] = a[i];
k++;
}
l -> length = k;
return l;
}
void partitionlist(SqList * list) {
int l = 0,r = list -> length - 1;
//让l指向头,r指向尾
int base = list -> data[0];
//将第一个数设置为基准
while(l < r) {
while(r > l && list -> data[r] > base)
r--;
//先从右往左遍历,找到第一个小于等于base的数
list -> data[l] = list -> data[r];
//将这个数放入l的位置上
while(l < r && list -> data[l] <= base)
l++;
//再从左往右,找到第一个大于base的数
list -> data[r] = list -> data[l];
//将这个数放在r的位置上
}
list -> data[l] = base;
//最后把这个数放在位置l处
}
//打印顺序表
void printlist(SqList *l) {
for(int i = 0; i < l -> length; i++) {
printf("%d ",l -> data[i]);
}
printf("\n");
}
int main() {
//创建顺序表
int arr[100];
arr[0] = 17;arr[1] = 2;arr[2] = 3;arr[3] = 5;arr[4] = 4;
arr[5] = 20;arr[6] = 1;arr[7] = 18;arr[8] = 19;arr[9] = 20;
arr[10] = 21;arr[11] = 6;arr[12] = 22;
SqList *l;
l = createlist(arr,13);
printf("初始的顺序表为:");
printlist(l);
//进行高效划分
partitionlist(l);
printf("高效划分后的顺序表为:");
printlist(l);
}