线性表分为顺序表和链表;链表由若干结点串联而成,结点在内存中的存储位置通常不连续;结点一般由数据域和指针域构成。
(1)malloc函数
接下来的解释终于是我搞懂了malloc语句的含义:
(2)new运算符
(3)内存泄漏
###(1)创建链表
###(2) 查找元素
###(3)插入元素
//链表的基本操作
#include <cstdio>
#include <cstdlib>
using namespace std;
struct node{//链表结点
int data;
node *next;
};
//创建链表
node *create(int Array[]){
node *p,*pre,*head;//pre保存当前结点的前驱结点,head为头结点
head = new node;//创建头结点
head->next = NULL;//头结点不需要数据域,指针域初始为NULL
pre = head;//记录pre为head
for(int i=0;i<5;i++){
p = new node;//新建结点
//将Array[i]赋值给新建的结点作为数据域,也可以scanf输入
p->data = Array[i];
p->next = NULL;//新结点的指针域设为NULL
pre->next = p;//前驱结点的指针域设为当前新建结点的地址
pre = p;//把pre设为p,作为下个结点的前驱结点
}
return head;//返回头结点指针
}
//查找元素
//以head为头结点的链表上计数元素x的个数
int search(node *head,int x){
int count = 0;//计数器
node *p = head->next;//从第一个结点开始
while(p != NULL){//只要没有到链表末尾
if(p->data == x){
count++;//当前结点数据域为x,则count++
}
p = p->next;//指针移动到下一结点
}
return count;//返回计数器count
}
//插入元素
//将x插入以head为头结点的链表的第pos个位置上
void insert(node *head,int pos,int x){
node *p = head;
for(int i = 0;i < pos - 1;i++){
p = p->next;//pos-1是为了到插入位置的前一个结点
}
node *q = new node;//新建结点
q->data = x;//新结点的数据域为x
q->next = p->next;//新结点的下一个结点指向原先插入位置的结点
p->next = q;//前一个位置的结点指向新结点
}
//删除元素
//删除以head为头结点的链表中的所有数据域为x的结点
void del(node *head,int x){
node *p = head->next;//p从第一个结点开始枚举
node *pre = head;//pre始终保存p的前驱结点的指针
while(p != NULL){
if(p->data == x){//数据域恰好为x,说明要删除该结点
pre->next = p->next;
delete(p);
p = pre->next;
}
else{//数据域不是x,把pre和p都后移一位
pre = p;
p = p->next;
}
}
}
int main(){
int Array[5] = {5,3,6,1,2};
node *L = create(Array);//新建链表,返回的头指针head赋值给L
L = L->next;//从第一个结点开始有数据域
while(L != NULL){
printf("%d",L->data);//输出每个结点的数据域
L = L->next;
}
return 0;
}
//7.3.4静态链表
struct Node{
typename data;//数据域
int next;//指针域
}node[size];
链接:
https://pintia.cn/problem-sets/994805342720868352/problems/994805460652113920
//PAT例题A1032Sharing
#include <iostream>
#include <cstdio>
#include <cstring>
const int maxn = 100010;
struct NODE{//静态链表
char data;//数据域
int next;//指针域
bool flag;//结点是否在第一条链表中出现
}node[maxn];
int main() {
for(int i=0;i<maxn;i++){
node[i].flag = false;
}
int s1,s2,n;//s1与s2分别代表两条链表的首地址n代表结点数
scanf("%d%d%d",&s1,&s2,&n);
int address,next;//结点地址与后继结点地址
char data;//数据
for(int i=0;i<n;i++){//输入结点数据
scanf("%d %c %d",&address,&data,&next);
node[address].data = data;
node[address].next = next;
}
int p;
for(p = s1;p != -1;p = node[p].next){
node[p].flag = true;//枚举第一条链表的所有结点,令其出现次数为1
}
for(p = s2;p != -1;p = node[p].next){
//找到第一个已经在第一条链表中出现的结点
if(node[p].flag == true) break;
}
if(p != -1){//如果第二条链表还没有到达结尾,说明找到了共用结点
printf("%05d\n",p);
}
else{
printf("-1\n");
}
return 0;
}
Contest100000607 - 《算法笔记》7.3小节——数据结构专题(1)->链表处理
链接: http://codeup.cn/contest.php?cid=100000607
提示:
1、因为输入数据中含有大量的插入和删除操作(不管你信不信,反正我信了),所以必须使用链表,否则很可能会超时。这也是考查链表的特性吧。
2、初始化链表的元素是倒序的,这个使用题目中创建列表的方法(从头部插入)就可以了。
总结:
这题考查的是链表的特性。顺序表中,怎样判断何时使用顺序表何时使用链表呢?就要看它们的特点了。顺序表的特点是随机存取、随机访问,也就是说如果存取和查询比较频繁的话使用顺序表比较合适;链表的特点是插入和删除时不必移动其后的节点,如果插入和删除操作比较频繁的话使用链表比较合适。
链接: http://codeup.cn/problem.php?cid=100000607&pid=0
//1326-ProblemA-算法2-8~2-11:链表的基本操作
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
typedef int Elemtype;
typedef int Status;
typedef struct LNode{
Elemtype data;
struct LNode *next;
}LNode,*LinkList;
void GetElem_L(LinkList &L,int i){
LinkList p;
p = L->next;
if(p==NULL)
{
printf("get fail\n");
return;
}
int j = 1;
while(p && j<i){
p = p->next;
++j;
}
if(!p || j>i){
printf("get fail\n");
return;
}
cout<<p->data<<endl;
// e = p->data;
return;
}
void ListInsert_L(LinkList &L,int i,Elemtype e){
LinkList p,s;
p = L;
int j = 0;
/*该插入方法无法判断差错出错和初始为空的插入之间的区别
while(p && j> i - 1){
p = p->next;
++j;
}
if(!p || j > i-1){
printf("insert fail\n");
return;
}
*/
for(int j=0;j<i-1;j++){
p = p->next;
if(p == NULL){
printf("insert fail\n");
return;
}
}
// return ERROR;
s = (LinkList)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
printf("insert OK\n");
return;
}
void ListDelete_L(LinkList &L,int i){
// LNode *p,*pre;
// p = L->next;
LNode *p = L->next;;
LNode *pre = L;
if(p == NULL){
printf("delete fail\n");
return;
}
for(int j=0;j<i-1;j++){
pre = p;
p = pre->next;
}
if(p ==NULL){
printf("delete fail\n");
return;
}
pre->next = p->next;
free(p);
printf("delete OK\n");
return;
}
void CreateList_L(LinkList &L,int n){
LinkList p;
int i;
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
for(i=n;i > 0;i--){
p = (LinkList)malloc(sizeof(LNode));
scanf("%d",&p->data);
p->next = L->next;
L->next = p;
}
}
void ListShow(LinkList &L){
LinkList p = L->next;
if(p == NULL){
printf("Link list is empty\n");
return;
}
while(p->next){
cout<<p->data<<" ";
p = p->next;
}
cout<<p->data<<endl;
}
int main(){
LinkList L;
int n;
cin>>n;//初始化链表n个元素
CreateList_L(L,n);
int op_num;
cin>>op_num;
while(op_num--){
// int del_number,get_number;
string str;
cin>>str;
if(str == "show"){
ListShow(L);
}
else if(str=="delete"){
int index;cin>>index;
ListDelete_L(L,index);
}
else if(str=="insert"){
int index,number;
cin>>index>>number;
ListInsert_L(L,index,number);
}
else if(str == "get"){
int index;cin>>index;
GetElem_L(L,index);
}
}
return 0;
}
链接: http://codeup.cn/problem.php?cid=100000607&pid=1
//1870-ProblemB-C语言-链表排序
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
struct student{
int no;//学号
int grade;//成绩
}stu[100010];
bool cmp(student x,student y){//结构体排序规则
return x.no < y.no;
}
int main(){
int N,M;
while(cin>>N>>M){
for(int i=0;i<N+M;i++){
cin>>stu[i].no>>stu[i].grade;
}
sort(stu,stu+N+M,cmp);
for(int i=0;i<N+M;i++){
cout<<stu[i].no<<" "<<stu[i].grade<<endl;
}
}
return 0;
}
链接: http://codeup.cn/problem.php?cid=100000607&pid=2
//2421-ProblemC-最快合并链表(线性表)
#include<iostream>
using namespace std;
//按先后顺序输出即可
int main() {
int n, m,num[100010];
/*
while (cin >> n) {
while (n--) {
cin >> x;
cout << x << " ";
}
cin >> m;
while (m--) {
cin >> x;
cout << x << " ";
}
*/
while(cin>>n){
for(int i=0;i<n;i++){
cin>>num[i];
}
int m;cin>>m;
int sum = m+n;
for(int i=n;i<sum;i++){
cin>>num[i];
}
// int sum = m+n;
int index;
for(index=0;index<sum-1;index++){
cout<<num[index]<<" ";
}
cout<<num[index]<<endl;
cout << endl;
}
return 0;
}
链接: http://codeup.cn/problem.php?cid=100000607&pid=3
// 2453-ProblemD-链表查找(线性表)
//非链表实现
#include<iostream>
using namespace std;
int main() {
int a[100010];
int x,n;
bool exisit = 0;
int index = 0;
while(cin>>x>>n){
for(int i=0;i<n;i++){
cin>>a[i];
if(x == a[i]){
exisit = i;
}
if(x>a[i-1] && x<a[i]){
index = i;
}
}
if(exisit){
int temp = a[exisit];
a[exisit] = a[exisit+1];
a[exisit+1] = temp;
for(int i=0;i<n-1;i++){
cout<<a[i]<<" ";
}
cout<<a[n-1]<<endl;
}
else{
cout<<"no"<<endl;
for(int i=n-1;i>=index;i--){
a[i+1]=a[i];
}
a[index] = x;
for(int i=0;i<n;i++){
cout<<a[i]<<" ";
}
cout<<a[n]<<endl;
}
}
return 0;
}
链接: http://codeup.cn/problem.php?cid=100000607&pid=4
//3596-ProblemE-算法2-24单链表反转
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;int a[100010];int cnt=0;
while(cin>>n){
if(!n){
cout<<"list is empty"<<endl;
break;
}
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n-1;i++){
cout<<a[i]<<" ";
}
cout<<a[n-1]<<endl;
reverse(a,a+n);
for(cnt=0;cnt<n-1;cnt++){
cout<<a[cnt]<<" ";
}
cout<<a[cnt]<<endl;
}
return 0;
}
链接: http://codeup.cn/problem.php?cid=100000607&pid=5
//3597-ProblemF-算法2-25有序单链表删除重复元素
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
int a[100010];
while(cin>>n){
int cnt = 0;
if(!n){
cout<<"list is empty"<<endl;
break;
}
for(int i=0;i<n;i++){
cin>>a[i];
}
//输出原序列
for(int i=0;i<n-1;i++){
cout<<a[i]<<" ";
}
cout<<a[n-1]<<endl;
//去除重复元素
for(int i=0;i<n;i++){//注意此处i从0到n-1,即使n-1+1=n没有输入数,因为需要将处理a[n-1]
if(a[i] != a[i+1]){//巧妙覆盖法
a[cnt++] = a[i];
}
}
//输出处理后的序列
for(int i=0;i<cnt-1;i++){//此处cnt++,所以a中最后一个数为a[cnt-1]
cout<<a[i]<<" ";
}
cout<<a[cnt-1]<<endl;
/*
5 1 2 3 4 5
5 1 1 2 2 3
0
*/
}
return 0;
}
线性表分为顺序表和链表;链表由若干结点串联而成,结点在内存中的存储位置通常不连续;结点一般由数据域和指针域构成。使用malloc函数或new运算符为链表结点分配内存空间,对应free()和delete()来释放内存;常用参数为创建链表、查找元素、插入元素、删除元素,具体可参考我的数据结构代码https://blog.csdn.net/qq_34767784/category_9061413.html