为什么要链表
因为数组有至少两个局限:
(1)编译期就要知道大小
(2)数组中的数据在计算机内存中是以相同的距离间隔开的,这意味在数组中插入一个数据,需要挪动数组中其他数据。
链表是好东西,实现链表最灵活的方法是指针。
以给出一组有序的序列后向序列中加入新的元素,且保证序列仍然有序为例
用数组模拟链表:
原理如图:
开俩个数组,一个用来存数一个用来存该数右边数的序号;
下面是刚学的时候对着图写的代码:
#include<bits/stdc++.h>
using namespace std;
int a[100001];
int b[100001];
int main()
{
int n;
cin>>n;
b[0]=1;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=i+1;
}
b[n]=0;//防止陷入死循环;
cin>>a[n+1];
int t;
for(t=0;;t=b[t])
{
if(a[b[t]]>a[n+1])
{
b[n+1]=b[t];
b[t]=n+1;
break;
}
}
int ti=1;
for(t=0;;t=b[t])
{
if(ti==n+2)break;
cout<<a[b[t]]<<" ";
ti++;
} cout<<endl;
return 0;
}
书上的代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[101],id[101];
int i,n,t,len;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
len=n;
len++;
for(int i=1;i<=n;i++)
{
if(i!=n)
id[i]=i+1;
else
id[i]=0;
}
cin>>a[len];
t=1;
while(t)
{
if(a[t]>a[len])
id[len]=id[t];
id[t]=len;
break;
}
t=1;
while(t)
{
cout<<a[t]<<" ";
t=id[t];
}
return 0;
}
但书上这样写有bug,就是当给出的元素比原序列第一个元素小的时候,不能正确排序;
改进后代码:
#include<bits/stdc++.h>
using namespace std;
int num[100010];
int nxt[100010];
int idx = 0, head = -1;
void odinsert(int x)//初始插入元素
{
nxt[idx] = head;
head = idx;
num[idx] = x;
idx++;
}
void del(int k)//删除k的一个后的元素;
{
nxt[k] = nxt[nxt[k]];
}
void nxtwinsert(int k, int x)//将x插入k位置;
{
num[idx] = x;
nxt[idx] = nxt[k];
nxt[k] = idx;
idx++;
}
int main()
{
int n;
cin>>n;
int a;
for(int i=0;i<n;i++)
{
cin>>a;
odinsert(a);
}
cin>>num[n];
for(int i=0;i<n;i++)
{
if(num[i]>num[n])
{
nxtwinsert(i,num[n]);
break;
}
}
while(nxt[head] != -1)//遍历出来是倒叙的;
{
cout << num[head] << " ";
head = nxt[head];
}
cout<<num[head];
cout << endl;
return 0;
}
结构体指针链表:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int num;
struct node *next;
};
int main()
{
int n;
scanf("%d",&n);
struct node *op,*np,*head=NULL,*flag;
int a;
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
np=(struct node*)malloc(sizeof(struct node));
np->next=NULL;
np->num=a;
if(head==NULL)
{
flag=np;
head=np;
}
else
op->next=np;
op=np;
}
scanf("%d",&a);
while(head!=NULL)
{
if(head->next->num >a)
{
np=(struct node *)malloc(sizeof(struct node));
np->num=a;
np->next=head->next;
head->next=np;
break;
}
head=head->next ;
}
while(flag!=NULL)
{
printf("%d ",flag->num);
flag=flag->next;
}
return 0;
}
链表的各种操作
创建节点:
typedef struct node
{
int num;
struct node;
}node;//声明node节点这个新类型
创建链表:
node* creat(int n)
{
node *head, *op,*np;
head = (node *)malloc(sizeof(node));
op = head; //头节点为0 加上头节点共n+1个节点
head->num = 0;
head->next = NULL;
int a;
for (int i = 1; i <= n; i++)
{
scanf("%d",&a);
node *np = (node *)malloc(sizeof(node));
np->num = a;
np->next = NULL;
op->next = np;
op = op->next;
}
return head;
}
node *creat(int n)
{
node *op,*np,*head=NULL;
int a;
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
np=(struct node*)malloc(sizeof(struct node));
np->next=NULL;
np->num=a;
if(head==NULL)
head=np;
else
op->next=np;
op=np;
}
return head;
}
输出链表:
void print(node *head)
{
node *pp=head->next ;//为了不改变head?
while(pp!=NULL)
{
printf("%d ",pp->num );
pp=pp->next;
}
}
删除节点:
void delet(int k,node *head)//删除值为k的节点
{
node *pre,*current;
pre=head;
current=head->next;
while(current!=NULL)
{
if(current->num==k)
{
pre->next=current->next;
free(current);
break;
}
pre=current;
current =current->next;
}
}
插入节点:
void insert(int k, node *head)//向链表头部插入节点
{
//创建新节点
node *np = (node *)malloc(sizeof(node));
np->num = k;
node* cun = head->next;
np->next = cun;
head->next = np;
}
应用:
n个人围成一圈,从第1个人开始顺序报号1,2,3。凡报到3者退出圈子。找出最后留在圈子中的人原来的序号。要求用链表实现。
首先看看非链表做法:即约瑟夫环 (先鸽着寒假再写)
#include<stdio.h>
int main()
{
int n;
while (scanf("%d", &n) != EOF)
{
int s = 0;
for (int i = 2; i <= n; i++)
{
s = (s + 3) % i;
}
printf("%d\n", s + 1);
}
return 0;
}
链表做法:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int num;
struct node *next;
}node;
node *creat(int n)
{
node *head,*np,*op;
head=(node*)malloc(sizeof(node));
head->num =0;
head->next =NULL;
op=head;
for(int i=1;i<=n;i++)
{
np=(node*)malloc(sizeof(node));
np->num =i;
np->next =NULL;
op->next =np;
op=np;
}
np->next =head->next ;
return head;
}
int main()
{
int n;
scanf("%d",&n);
node *head=creat(n);
int i=0;
node *pre,*cur;
cur=head->next ;
pre=NULL;
int flag=-1;
while(1)
{
i++;
if(flag==cur->num)
break;
flag=cur->num ;
if(i==3)
{
pre->next =cur->next ;
free(cur);
i=0;
}
pre=cur;
cur=cur->next;
}
printf("%d",flag);
return 0;
}
具体到每一步:
#include <stdio.h>
struct people
{
int id;//记录报的数
struct people *next;
};
int main()
{
int n;
scanf("%d",&n);
int count = n;
people p[n];
people *head;
head = p; //head 指向p[0]
for (int i = 0; i < n; i++)
{
head->id = i + 1;
head->next = &p[i + 1];
head = head->next;
}
//最后一个元素指向第一个元素 ,从而 形成环
p[n - 1].next = p;
int i = 1;
head = p;
while (count > 1)
{
//跳过已经被淘汰的节点
if (head->id == 0)
{
head = head->next;
continue;
}
if (i == 3)
{
//被淘汰的节点,n置为0
printf("第 %d 位置被淘汰\n", head->id);
head->id = 0;
count--;
}
head = head->next;
i++;
if (i > 3)
{
i = 1;
}
}
printf("--------------\n");
while (head->id == 0)
{
//非0节点即为最后留下的
head = head->next;
if (head->id != 0)
{
printf("留到最后的是 %d \n", head->id);
}
}
return 0;
}