链表--部分知识点整理
1、建立单链表:
下面两种方法的时间复杂度都是O(n)
(1)头插法
Linklist CreateFromHead(){
LinkList L;
LNode *s;
int x;
int flag=1;
L=(Linklist)malloc(sizeof(LNode));
L->next=NULL;
scanf("%d",&x);
while(x!=-1){
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
s->next=L->next;
L->next=s;
scanf("%d",&x);
}
return L;
}
每次都相当于在头结点后面插入新元素
(2)尾插法
Linklist CreateFromTail(){
LinkList L;
LNode *r,*s;
int x;
L=(LNode *)malloc(sizeof(LNode));
L->next=NULL;
r=H;//指向头结点
scanf("%d",&x);
while(x!=-1){
s=(LNode*)malloc(sizeof(LNode));
s->data=x;
s->next=r->next;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
有一个尾指针r始终指向最后一个节点
2、循环列表
举个例子:有两个带头结点的循环单链表LA、LB,编写一个算法,将两个循环单链表合并为一个循环单链表,其头指针为LA
分析:
第一种情况,先找到两个链表的尾,分别用指针p、q指向它们,然后将第一个链表的尾与第二个链表的第一个结点链接起来,并修改第二个链表的尾节点,使它的链域指向第一个链表的头结点,并且释放第二个链表的头结点
LinkList merge_1(LinkList LA,LinkList LB){
LNode *p,*q;
p=LA;
q=LB;
while(p->next!=LA)
p=p->next;
while(q->next!=LB)
q=q->next;
p->next=LB->next;
free(LB);
q->next=LA;
return(LA);
}
时间复杂度为O(n)
第二种情况,当上面的两个循环链表带有尾指针时,又怎么合并呢?
LinkList merge_2(LinkList RA,LinkList RB)
{
LNode *p;
p=RA->next;
RA->next=RB->next->next;
free(RB->next);
RB->next=p;
return(RB);
}
时间复杂度为O(1)
循环链表实现约瑟夫环
约瑟夫环问题,是一个经典的循环链表问题,题意是:已知 n 个人(分别用编号 1,2,3,…,n 表示)围坐在一张圆桌周围,从编号为 k 的人开始顺时针报数,数到 m 的那个人出列;他的下一个人又从 1 开始,还是顺时针开始报数,数到 m 的那个人又出列;依次重复下去,直到圆桌上剩余一个人。
如图所示,假设此时圆周周围有 5 个人,要求从编号为 3 的人开始顺时针数数,数到 2 的那个人出列:
出列顺序依次为:
- 编号为 3 的人开始数 1,然后 4 数 2,所以 4 先出列;
- 4 出列后,从 5 开始数 1,1 数 2,所以 1 出列;
- 1 出列后,从 2 开始数 1,3 数 2,所以 3 出列;
- 3 出列后,从 5 开始数 1,2 数 2,所以 2 出列;
- 最后只剩下 5 自己,所以 5 胜出。
约瑟夫环问题有多种变形,比如顺时针转改为逆时针等,虽然问题的细节有多种变数,但解决问题的中心思想是一样的,即使用循环链表。
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int number;
struct node * next;
}person;
person * initLink(int n){
person * head=(person*)malloc(sizeof(person));
head->number=1;
head->next=NULL;
person * cyclic=head;
for (int i=2; i<=n; i++) {
person * body=(person*)malloc(sizeof(person));
body->number=i;
body->next=NULL;
cyclic->next=body;
cyclic=cyclic->next;
}
cyclic->next=head;//首尾相连
return head;
}
void findAndKillK(person * head,int k,int m){
person * tail=head;
//找到链表第一个结点的上一个结点,为删除操作做准备
while (tail->next!=head) {
tail=tail->next;
}
person * p=head;
//找到编号为k的人
while (p->number!=k) {
tail=p;
p=p->next;
}
//从编号为k的人开始,只有符合p->next==p时,说明链表中除了p结点,所有编号都出列了,
while (p->next!=p) {
//找到从p报数1开始,报m的人,并且还要知道数m-1de人的位置tail,方便做删除操作。
for (int i=1; i<m; i++) {
tail=p;
p=p->next;
}
tail->next=p->next;//从链表上将p结点摘下来
printf("出列人的编号为:%d\n",p->number);
free(p);
p=tail->next;//继续使用p指针指向出列编号的下一个编号,游戏继续
}
printf("出列人的编号为:%d\n",p->number);
free(p);
}
int main() {
printf("输入圆桌上的人数n:");
int n;
scanf("%d",&n);
person * head=initLink(n);
printf("从第k人开始报数(k>1且k<%d):",n);
int k;
scanf("%d",&k);
printf("数到m的人出列:");
int m;
scanf("%d",&m);
findAndKillK(head, k, m);
return 0;
}
3、双向链表
更方便的获得一个结点的前驱和后继结点,方便插入和删除
在单链表的每个结点里再增加一个指向其前驱的指针域prior
#include <stdio.h>
#include <stdlib.h>
typedef struct dList{
struct dList * prior;
int data;
struct dList * next;
}dList;
//双链表的创建
dList* initdList(dList * head);
//双链表插入元素,add表示插入位置
dList * insertdList(dList * head,int data,int add);
//双链表删除指定元素
dList * deldList(dList * head,int data);
//双链表中查找指定元素
int selectElem(dList * head,int elem);
//双链表中更改指定位置节点中存储的数据,add表示更改位置
dList *amendElem(dList * p,int add,int newElem);
//输出双链表的实现函数
void display(dList *head);
int main() {
dList *head=NULL;
//创建双链表
head=initdList(head);
display(head);
//在表中第 3 的位置插入元素 7
head=insertdList(head, 7, 3);
display(head);
//表中删除元素 2
head=deldList(head, 2);
display(head);
printf("元素 3 的位置是:%d\n",selectElem(head,3));
//表中第 3 个节点中的数据改为存储 6
head = amendElem(head,3,6);
display(head);
return 0;
}
dList* initdList(dList * head){
head=(dList*)malloc(sizeof(dList));
head->prior=NULL;
head->next=NULL;
head->data=1;
int i;
dList * list=head;
for (i=2;i<=5;i++) {
dList *body=(dList*)malloc(sizeof(dList));
body->prior=NULL;
body->next=NULL;
body->data=i;
list->next=body;
body->prior=list;
list=list->next;
}
return head;
}
dList *insertdList(dList *head,int data,int add){
int i;
//新建数据域为data的结点
dList *temp=(dList*)malloc(sizeof(dList));
temp->data=data;
temp->prior=NULL;
temp->next=NULL;
//插入到链表头,要特殊考虑
if (add==1) {
temp->next=head;
head->prior=temp;
head=temp;
}else{
dList * body=head;
//找到要插入位置的前一个结点
for (i=1; i<add-1; i++) {
body=body->next;
}
//判断条件为真,说明插入位置为链表尾
if (body->next==NULL) {
body->next=temp;
temp->prior=body;
}else{
body->next->prior=temp;
temp->next=body->next;
body->next=temp;
temp->prior=body;
}
}
return head;
}
dList *deldList(dList * head,int data){
dList *temp=head;
//遍历链表
while (temp) {
//判断当前结点中数据域和data是否相等,若相等,摘除该结点
if (temp->data==data) {
temp->prior->next=temp->next;
temp->next->prior=temp->prior;
free(temp);
return head;
}
temp=temp->next;
}
printf("链表中无该数据元素");
return head;
}
//head为原双链表,elem表示被查找元素
int selectElem(dList * head,int elem){
//新建一个指针t,初始化为头指针 head
dList * t=head;
int i=1;
while (t) {
if (t->data==elem) {
return i;
}
i++;
t=t->next;
}
//程序执行至此处,表示查找失败
return -1;
}
//更新函数,其中,add 表示更改结点在双链表中的位置,newElem 为新数据的值
dList *amendElem(dList * p,int add,int newElem){
dList * temp=p;
int i;
//遍历到被删除结点
for (i=1; i<add; i++) {
temp=temp->next;
}
temp->data=newElem;
return p;
}
//输出链表的功能函数
void display(dList * head){
dList * temp=head;
while (temp) {
if (temp->next==NULL) {
printf("%d\n",temp->data);
}else{
printf("%d->",temp->data);
}
temp=temp->next;
}
}
4、线性表实现一元多项式的表示和加减乘运算
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef struct polyn
{
float coef;
int expn;
struct polyn* next;
}PolyNode,*PLinkList;
PLinkList CreatePolyn();//创建一元多项式,使一元多项式呈指数递减
void OutPut(PLinkList head);//输出一元多项式
PLinkList Addition(PLinkList L1,PLinkList L2);//多项式的加法
PLinkList Subtraction(PLinkList L1,PLinkList L2);//多项式的减法
PLinkList Reverse(PLinkList head);//将生成的链表逆置。使一元多项式呈指数递增形式
PLinkList MultiplyPolyn(PLinkList L1,PLinkList L2);//多项式的乘法
PLinkList CreatePolyn()//创建一元多项式。使一元多项式呈指数递减
{
PolyNode *p,*q,*s;
PolyNode *head = NULL;
int expn2;
float coef2;
head = (PLinkList)malloc(sizeof(PolyNode));//动态生成头结点
if(!head)
{
return NULL;
}
head->coef = 0.0;//初始化
head->expn = 0;
head->next = NULL;
do
{
printf("输入系数coef(系数和指数都为0结束)");
scanf("%f",&coef2);
printf("输入指数数exp(系数和指数都为0结束)");
scanf("%d",&expn2);
if((long)coef2 == 0 && expn2 == 0)
{
break;
}
s = (PLinkList)malloc(sizeof(PolyNode));
if(!s)
{
return NULL;
}
s->expn = expn2;
s->coef = coef2;
q = head->next ;
p = head;
while(q && expn2 < q->expn)
{
p = q;
q = q->next ;
}
if(q == NULL || expn2 > q->expn)
{
p->next = s;
s->next = q;
}
else
{
q->coef += coef2;
}
}while(1);
return head;
}
void OutPut(PLinkList head)//输出一元多项式
{
PolyNode *p = head->next ;
while(p)
{
printf("%1.1f",p->coef);
if(p->expn)
{
printf("*x^%d",p->expn);
}
if(p->next && p->next->coef > 0)
{
printf("+");
}
p = p->next ;
}
}
PolyNode *Addition(PLinkList L1,PLinkList L2)//多项式的加法
{
PolyNode *pa,*pb,*pc,*u,*head;
head = (PLinkList)malloc(sizeof(PolyNode));
if(!head)
{
return NULL;
}
head->coef = 0.0;
head->expn = 0;
head->next = NULL;
pc = head;
L2 = Reverse(L2);
pa = L1->next ;
pb = L2->next ;
while(pa != NULL && pb != NULL)
{
if(pa->expn == pb->expn)
{
u = (PLinkList)malloc(sizeof(PolyNode));
if(!u)
{
return NULL;
}
u->coef = pa->coef + pb->coef ;
u->expn = pa->expn ;
pa = pa->next ;
pb = pb->next ;
u->next = pc->next ;
pc->next = u;
pc = u;
}
else if(pa->expn > pb->expn)
{
u = (PLinkList)malloc(sizeof(PolyNode));
if(!u)
{
return NULL;
}
u->coef = pa->coef ;
u->expn = pa->expn ;
pa = pa->next ;
u->next = pc->next ;
pc->next = u;
pc = u;
}
else
{
u = (PLinkList)malloc(sizeof(PolyNode));
if(!u)
{
return NULL;
}
u->coef = pb->coef ;
u->expn = pb->expn ;
pb = pb->next ;
u->next = pc->next ;
pc->next = u;
pc = u;
}
}
L2 = Reverse(L2);
return head;
}
PolyNode *Subtraction(PLinkList L1,PLinkList L2)//多项式的减法
{
PolyNode *pa,*pb,*pc,*u,*head;
head = (PLinkList)malloc(sizeof(PolyNode));
if(!head)
{
return NULL;
}
head->coef = 0.0;
head->expn = 0;
head->next = NULL;
pc = head;
pa = L1->next ;
pb = L2->next ;
while(pa != NULL && pb != NULL)
{
if(pa->expn == pb->expn)
{
u = (PLinkList)malloc(sizeof(PolyNode));
if(!u)
{
return NULL;
}
u->coef = pa->coef - pb->coef ;
u->expn = pa->expn ;
pa = pa->next ;
pb = pb->next ;
u->next = pc->next ;
pc->next = u;
pc = u;
}
else if(pa->expn > pb->expn)
{
u = (PLinkList)malloc(sizeof(PolyNode));
if(!u)
{
return NULL;
}
u->coef = pa->coef ;
u->expn = pa->expn ;
pa = pa->next ;
u->next = pc->next ;
pc->next = u;
pc = u;
}
else
{
u = (PLinkList)malloc(sizeof(PolyNode));
if(!u)
{
return NULL;
}
u->coef = pb->coef ;
u->expn = pb->expn ;
pb = pb->next ;
u->next = pc->next ;
pc->next = u;
pc = u;
}
}
return head;
}
PolyNode *Reverse(PLinkList head)//将生成的链表逆置,使一元多项式呈指数递增形式
{
PolyNode *q,*r,*p = NULL;
q = head->next ;
while(q)
{
r = q->next ;
q->next = p;
p = q;
q = r;
}
head->next = p;
return head;
}
PolyNode *MultiplyPolyn(PLinkList L1,PLinkList L2)//多项式的乘法
{
PolyNode *pa,*pb,*pc,*u,*head;
int k,maxExp;
float coef;
head = (PLinkList)malloc(sizeof(PolyNode));
if(!head)
{
return NULL;
}
head->coef = 0.0;
head->expn = 0;
head->next = NULL;
if(L1->next != NULL && L2->next != NULL)
{
maxExp = L1->next->expn +L2->next->expn ;
}
else
{
return head;
}
pc = head;
L2 = Reverse(L2);
for(k = maxExp;k >= 0;k--)
{
pa = L1->next ;
while(pa != NULL && pa->expn > k)
{
pa = pa->next ;
}
pb = L2->next ;
while(pb != NULL && pa != NULL && pa->expn+pb->expn < k)
{
pb= pb->next ;
}
coef = 0.0;
while(pa != NULL && pb != NULL)
{
if(pa->expn +pb->expn == k)
{
coef += pa->coef *pb->coef ;
pa = pa->next ;
pb = pb->next ;
}
else if(pa->expn +pb->expn > k)
{
pa = pa->next ;
}
else
{
pb = pb->next ;
}
}
if(coef != 0.0)
{
u = (PLinkList)malloc(sizeof(PolyNode));
u->coef = coef;
u->expn = k;
u->next = pc->next ;
pc->next = u;
pc = u;
}
}
L2 = Reverse(L2);
return head;
}
//测试
int main(void)
{
PLinkList A,B,C,D,E;
A = CreatePolyn();
printf("A(x) =");
OutPut(A);
printf("\n");
B = CreatePolyn();
printf("B(x) =");
OutPut(B);
printf("\n");
C = MultiplyPolyn(A,B);
printf("C(x) = A(x)*B(x) =");
OutPut(C);
printf("\n");
D = Addition(A,B);
printf("D(x) = A(x)+B(x) =");
OutPut(D);
printf("\n");
E = Subtraction(A,B);
printf("E(x) = A(x)-B(x) =");
OutPut(E);
printf("\n");
return 0;
}