1.链表相关知识
In object-oriented programming languages, lists are usually provided
as instances of subclasses of a generic “list” class, and traversed
via separate iterators.
在面向对象的编程语言中,列表通常作为一个通用的“列表”类的子类的实例提供,并通过不同的迭代器遍历。
2.构建链表代码
#include <stdio.h>
#include <stdlib.h>
struct node
{
int num;
struct node*next;
};
struct node*creat(int n)//链表的录入
{
struct node*head,*p,*q;
head = (struct node*)malloc(sizeof(struct node));
head->next = NULL;
q = head;
for(int i = 1;i<=n;i++)
{
p = (struct node*)malloc(sizeof(struct node));
scanf("%d",&p->num);
p->next = NULL;
q->next = p;
q = p;
}
return head;
}
void show(struct node*head)//链表的输出
{
struct node*tail;
tail = head->next;
while(tail!=NULL)
{
if(tail->next==NULL)
printf("%d\n",tail->num);
else
printf("%d ",tail->num);
tail = tail->next;
}
}
int main()
{
int n;
scanf("%d",&n);
struct node*head;
head = creat(n);
show(head);
return 0;
}
3.链表构造详细
代码来源
①创造节点
struct NODE{//结点数据类型
ElemType data;//数据域(即链表中的数据对象/元素)
NODE *link;//指针域
};
一个结点中的link成员是用来指向另一个结点。
ElemType(也有的书上称之为elemtp)是数据结构的书上为了说明问题而用的一个词。它是element type(“元素的类型”)的简化体。
因为数据结构是讨论抽象的数据存储和算法的,一种结构中元素的类型不一定是整型、字符型、浮点型或者用户自定义类型,为了不重复说明,使用过程中用"elemtype"代表所有可能的数据类型,简单明了的概括了整体。在算法中,除特别说明外,规定ElemType的默认是int型。
链表通过指针实现连接,而不是连续内存。
增加了存储空间的利用率。
②
为了不在指向结点时不断应用*符号,创建一个指针类型listlink。
typeof NODE* linklist;//linklist是单链表指针,专门指向结点
linklist p;
p=new NODE;//通过内存动态分配产生新结点的内存单元
③创建链表常用的两种方法:
void input(Elemtype *ep){//数据域元素输入
cin >> *ep;
}
①头插法
void CreateLinkF(Linklist *L,int n,void(*input)(*Elemtype))
//传递的是指针的地址 //指向input的函数
//用来接收指针就是指针的指针,因为接收的
//头插法创建单链表,调用input输入函数输入数据
{
LinkList s;
*L=new NODE;//创建头结点
(*L)->next = NULL;//初始时为空表
for(;n>0;n--){//创建n个结点链表
s=new NODE;
input(&s->data);
//*L始终指向头结点
s->next=(*L)->next;//第一次给s的指针域赋空值
/*第二次开始把上一个创建的结点地址存放到新建的指针之中
即把上一个结点移到开始结点之前。*/
(*L)->next=s;//把新创建的头结点之后
}
}
实际是在改变地址存放位置。
主调函数
int main()
{
LinkList L;
int n;
cin>>n;
CreateLinkF(&L,n,input);
}
②尾插法
void CreateLinkR(Linklist *L,int n,void(*input)(*Elemtype))
{
LinkList p,s;
p=*L=new NODE;//都指向头结点
for(;n>0;n--){//创建n个结点链表
s=new NODE;//创建新结点
input(&s->data);//调用input输入
p->next=s,p=s;//将s插入当前链表末尾
}
p->next=NULL;//尾结点
}
即不断将结点的指针指向下一个(新创建)结点,再让p代表新创建的结点。
4.如何销毁链表
void DestroyList(LinkList *L)
{
LinkList q,p=*L;//p指向头结点,p指向起始结点;
while(p!=NULL){
q=p->next;
delete p;
p=q;
}
*L=NULL;//头指针赋成空值,置为空表
}
p从头结点逐渐往后移,一直删除到没有结点可删除。
5.链表的分类
(1)单链表
头结点数据域一般不放东西,为NULL。
而开始结点中数据域不为空。
(2)双链表
优点:有两条链,保证安全。(即一条链断了第二条链仍能使用)
(3)循环链表
尾结点next指向头结点。
☆循环双链表:
即头结点prev指向尾结点而不是0,尾结点next指向头结点。
6.链表的运算(4.6更新)
链表的遍历代码
void ListTraverse(LinkList L,void(*visit)(ElemType*))
{//遍历L中的每个元素且调用函数visit访问它
LinkList p=L->next;//p指向开始结点
while(p!=NULL){
visit(&(p->data));
p=p->next;//p指向直接后继结点
}
}
[部分操作]
1.If delete the second node:
node* save = head->next;
head->next = head->next->next;
free(save);
2.If append a node at the end of the list
node* last = head;
while(last->next != NULL) {
last = last->next;
}
last->next = (node*)malloc(sizeof(node));
last->next->data = data;
last->next->next = NULL;
3.Traversal
node * temp = head;
while(temp != NULL) {
Traversal(temp);
temp = temp->next;
}