1.特征:
①链表中的元素个数可以根据需要增加和减少,不像数组,在声明之后就固定不变;
②元素的位置可以变化,即可以从某个位置删除,然后再插入到一个新的地方;
2.组成:数据成员和指针存放下一个结点的地址(链表中的各节点在内存的存储地址不是连续的)
3.基本操作:
(1)创建链表是指,从无到有地建立起一个链表,即往空链表中依次插入若干结点,并保持结点之间的前驱和后继关系。
(2)检索操作是指,按给定的结点索引号或检索条件,查找某个结点。如果找到指定的结点,则称为检索成功;否则,称为检索失败。
(3)插入操作是指,在结点ki-1与ki之间插入一个新的结点k’,使线性表的长度增1,且ki-1与ki的逻辑关系发生如下变化:插入前,ki-1是ki的前驱,ki是ki-1的后继;插入后,新插入的结点k’成为ki-1的后继、ki的前驱。
(4)删除操作是指,删除结点ki,使线性表的长度减1,且ki-1、ki和ki+1之间的逻辑关系发生如下变化:删除前,ki是ki+1的前驱、ki-1的后继;删除后,ki-1成为ki+1的前驱,ki+1成为ki-1的后继.
(5)打印输出
4.链表结构体定义:struct node { int num; struct node *next; }
6.结点指针定义:node *p;
7.结点存储空间申请、释放:p = new node;/delete p;
8.种类:链表又分为单链表、双向链表和循环链表
9.创建:
1 ) 定义链表的数据结构。
2 ) 创建一个空表。
3 ) 利用new( )函数向系统申请分配一个节点。
4 ) 将新节点的指针成员赋值为空(保证最后一个元素指针指向NULL)。若是空表,将新节点连接到表头;若是非空表,将新节点接到表尾。
5 ) 判断一下是否有后续节点要接入链表,若有转到3 ),否则结束。
</pre>典型的链表创建、遍历模板:<pre name="code" class="cpp">#include<stdio.h>
#include<malloc.h>
struct node
{
int data ; //数据域
struct node *next ; //指针域,指向下一个结点
};
int main()
{
int n; //将要输入的结点的个数
scanf("%d",&n);
struct node *head = (struct node *)malloc(sizeof(struct node)); //为头结点申请存储空间
head->next = NULL; //现在是空链表,头结点的next为空
struct node *tail = head; //tail是指向链表的最后一个结点
for(int i = 1;i <= n;i++ )
{
struct node *p=(struct node *)malloc(sizeof(struct node)); //为新结点申请存储空间
scanf("%d",&p->data); //输入新结点的数据
p->next=head->next;; //因为要与输入顺序一致,所以每次输入的值为当前链表的第一个结点
head->next=p;
}
struct node *s=head->next; //将s指向链表的第一个结点
while(s->next!=NULL) //判断是否是链表最后一个元素就是要判断该元素的next指针是否为空
{
printf("%d ",s->data);
s=s->next; //s移向先一个结点
}
printf("%d\n",s->data); //输出最后一个结点的数据并输出换行
return 0;
}
10.例题:UVA-11988 这个代码会TLE,但是思路对,这是建表的一个好的练习
#include<stdio.h>
#include<time.h>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<iostream>
#include<vector>
using namespace std;
struct node
{
char n;node *next;
};
int main()
{
char t[100005];
while(scanf("%s",t) != EOF)
{
node *last = new node; //创建尾部,
last->next =NULL; //指明尾部指针
node *tou = last; //创建头部并指明头部指针
node *lastt = last;
int len = strlen(t);
for(int i = 0;i < len;i++)
{
if(t[i] == '[')
{
last = tou;
last->next = tou->next;
}
else if(t[i] == ']')
{
node *temp = last;
while(temp->next != NULL)
{
temp = temp->next;
}
last = temp;
}
else
{
node *u = new node; //创建子节点
if(last->next == NULL) //接上元素
u->next = NULL;
else //插入元素
u->next = last->next;
last->next = u;
u->n = t[i];
last = u; //子节点移动
}
}
node *u = tou->next;
while(1)
{
if(u == NULL) break;
printf("%c",u->n);
u = u->next;
}
printf("\n");
}
return 0;
}
以下是刘汝佳的思路:
#include<stdio.h>
#include<iostream>
#include<string>
#include<stack>
#include<string.h>
using namespace std;
int last,cur,next[100005];
char s[100005];
int main()
{
while(scanf("%s",s+1)!=EOF)
{
int len=strlen(s+1);
last=cur=0;
next[0]=0;
for(int i=1;i<=len;i++)
{
if(s[i]=='[') cur=0;
else
if(s[i]==']') cur=last;
else
{
next[i]=next[cur];
next[cur]=i;
if(cur == last) last = i;
cur = i;
}
}
for(int i=next[0];i!=0;i=next[i])
printf("%c",s[i]);
printf("\n");
}
return 0;
}
11.STL链表:
①定义:list<int(任意类型)> name;
②头文件:#include<list>
③push_back()、push_front():往链表后面/前面填元素
④empty():判断链表是否为空
⑤begin()、end():返回链表的第一、最后一个元素
⑥链表遍历:
#include <iostream>
#include <string>
#include <list>
int main (void)
{
list<string> Milkshakes;
list<string>::iterator MilkshakeIterator; //定义迭代器类型
Milkshakes.push_back("Chocolate");
Milkshakes.push_back("Strawberry");
Milkshakes.push_front("Lime");
Milkshakes.push_front("Vanilla");
Milkshakes.push_front("The Milkshake Menu");
Milkshakes.push_back("*** Thats the end ***");
for (MilkshakeIterator=Milkshakes.begin();MilkshakeIterator!=Milkshakes.end();++MilkshakeIterator) //遍历链表(访问了链表中的所有元素),注意不包含最后一个元素
cout << *MilkshakeIterator << endl;
}
注:这个list容器,就象你所想的,它不支持在iterator加一个数来指向隔一个的对象。 就是说,我们不能用Milkshakes.begin()+2来指向list中的第三个对象,因为STL的list是以双链的list来实现的, 它不支持随机存取。
⑦for_each()遍历:
#include <iostream.h>
#include <string>
#include <list>
#include <algorithm>
PrintIt (string& StringToPrint)
{
cout << StringToPrint << endl;
}
int main (void)
{
list<string> FruitAndVegetables;
FruitAndVegetables.push_back("carrot");
FruitAndVegetables.push_back("pumpkin");
FruitAndVegetables.push_back("potato");
FruitAndVegetables.push_front("apple");
FruitAndVegetables.push_front("pineapple");
for_each (FruitAndVegetables.begin(), FruitAndVegetables.end(), PrintIt); //最后一个是要做的事(一定要是函数吗?)
}
⑧count():
#include <list>
#include <algorithm>
int main (void)
{
list<int> Scores;
Scores.push_back(100);
Scores.push_back(80);
Scores.push_back(45);
Scores.push_back(75);
Scores.push_back(99);
Scores.push_back(100);
int NumberOf100Scores(0);
NumberOf100Scores = count(Scores.begin(), Scores.end(), 100); //当元素为100时,<span style="font-family: Arial, Helvetica, sans-serif;">NumberOf100Scores自增</span>
cout << "There were " << NumberOf100Scores << " scores of 100" << endl;
}
⑨ count_if():
⑩find():
#include <string>
#include <list>
#include <algorithm>
int main (void)
{
list<string> Fruit;
list<string>::iterator FruitIterator;
Fruit.push_back("Apple");
Fruit.push_back("Pineapple");
Fruit.push_back("Star Apple");
FruitIterator = find (Fruit.begin(), Fruit.end(), "Pineapple"); //返回值是一个迭代器
if (FruitIterator == Fruit.end()) cout << "Fruit not found in list" << endl;
else cout << *FruitIterator << endl;
}
⑾remove():用remove()算法返回一个指向新的list的结尾的iterator。从开始到这个新的结尾(不含新结尾元素)的范围 包含了remove后剩下所有元素。你可以用list成员函数erase函数来删除从新结尾到老结尾的部分。一共有两种remove
#include <string>
#include <list>
#include <algorithm>
PrintIt(string& AString) { cout << AString << endl; }
int main (void)
{
list<string> Birds;
list<string>::iterator NewEnd;
Birds.push_back("cockatoo");
Birds.push_back("galah");
Birds.push_back("cockatoo");
Birds.push_back("rosella");
Birds.push_back("king parrot");
cout << "Original list" << endl;
for_each(Birds.begin(), Birds.end(), PrintIt);
NewEnd = remove(Birds.begin(), Birds.end(), "cockatoo"); //最后一个输入要删除的元素,返回新的结尾迭代器
cout << endl << "List according to new past the end iterator" << endl;
for_each(Birds.begin(), NewEnd, PrintIt);
cout << endl << "Original list now. Care required!" << endl;
for_each(Birds.begin(), Birds.end(), PrintIt);
}
#include <string> //
#include <list>
#include <algorithm>
PrintIt (const string& StringToPrint)
{
cout << StringToPrint << endl;
}
int main (void)
{
list<string> Birds;
Birds.push_back("cockatoo");
Birds.push_back("galah");
Birds.push_back("cockatoo");
Birds.push_back("rosella");
Birds.push_back("corella");
cout << "Original list with cockatoos" << endl;
for_each(Birds.begin(), Birds.end(), PrintIt);
Birds.remove("cockatoo");
cout << "Now no cockatoos" << endl;
for_each(Birds.begin(), Birds.end(), PrintIt);
}
⑿insert() :
#include <list>
int main (void)
{
list<int> list1;
for (int i = 0; i < 10; ++i) list1.push_back(i);
list1.insert(list1.begin(), -1);
list1.insert(list1.end(), 10);
int IntArray[2] = {11,12};
list1.insert(list1.end(), &IntArray[0], &IntArray[2]);
}
⒀