数据结构:链表

在这里给出数组实现单链表和双链表以及指针实现单链表和双链表的例子,为以后更为复杂的数据结构实现打基础。

首先介绍一下使用数组来实现链表的原理

int node[maxn];
int cur=0;
int Next[maxn];
int tot=0;

node数组是用来保存所有的节点的取值的,这里面的节点是程序生成的流水节点,其真正有没有出现在链表中是没有任何关系的

cur用来指示当前在node数组中的哪一个位置,是一个位置变量

Next数组用来存node数组中下标位置的节点所连接的下一个元素在node数组中的下标,是链表的核心

tot用来记录当前链表中有多少个节点

先是单链表

接下来我们给出其中最主要的函数的定义,insert_back函数

void insert_back(int a,int s)
{
    cur++;
    node[cur]=s;
    Next[cur]=Next[a];
    Next[a]=cur;
}

这个函数的用途是在链表a位置的元素后面插入一个新的值为s的节点

首先第一步是把新节点赋值之后加入到node数组的尾部

接下来要做的就是插入了,让新节点的下一个元素指向a节点之前指向的元素

然后让a节点的下一个元素指向新节点

下面给出单链表数组实现的完整程序

 1 #include<iostream>
 2 using namespace std;
 3 const int maxn=1005; 
 4 int n;
 5 int node[maxn];
 6 int cur=0;
 7 int Next[maxn];
 8 int tot=0;
 9 void insert(int a,int b,int s)
10 {
11     cur++;
12     node[cur]=s;
13     Next[a]=cur;
14     Next[cur]=b;
15 }
16 void insert_back(int a,int s)
17 {
18     cur++;
19     node[cur]=s;
20     Next[cur]=Next[a];
21     Next[a]=cur;
22 }
23 void insert_front(int b,int s)
24 {
25     cur++;
26     node[cur]=s;
27     Next[cur]=b;
28     int a;
29     for(int i=1;i<=cur;i++)
30     {
31         if(Next[i]==b)
32         {
33             a=i;
34             break;
35         } 
36     }
37     Next[a]=cur;
38 }
39 void _delete(int a,int b)
40 {
41     Next[a]=b;
42 }
43 void delete_back(int a)
44 {
45     Next[a]=Next[Next[a]];
46 }
47 void delete_front(int b)
48 {
49     int s;
50     for(int i=1;i<=cur;i++)
51     {
52         if(Next[i]==b)
53         {
54             s=i;
55             break;
56         }
57     }
58     int a;
59     for(int i=1;i<=cur;i++)
60     {
61         if(Next[i]==s)
62         {
63             a=i;
64             break;
65         }
66     }
67     Next[a]=b;
68 }
69 int main()
70 {
71     cin>>n;
72     int tmp;
73     cin>>tmp;
74     insert_back(0,tmp);
75     tot++;
76     for(int i=1;i<n;i++)
77     {
78         cin>>tmp;
79         insert_back(i,tmp);
80         tot++;
81     }
82     tmp=Next[0];
83     while(tmp)
84     {
85         cout<<node[tmp]<<" ";
86         tmp=Next[tmp];
87     }
88     return 0; 
89 }

然后我们介绍双链表的数组实现

int node[maxn]; 
int Prev[maxn];
int Next[maxn];
int cur;
int tot=0;

在原来的基础上新加入了一个数组,用来表示下标位置节点的前一个节点在node数组中的下标

然后我们还是以insert_back函数为例子

void insert_back(int a,int s)
{
    cur++;
    node[cur]=s;
    Prev[Next[a]]=cur;
    Next[cur]=Next[a];
    
    Prev[cur]=a;
    Next[a]=cur;
}

首先将新节点放入node数组中

让a节点的下一个节点的前驱节点指向新节点

让a节点的下一个节点成为新节点的后继

让新节点的前驱节点指向a节点

让a节点的后继节点指向新节点

下面给出完整的双链表的数组实现程序

 1 #include<iostream>
 2 using namespace std;
 3 const int maxn=1005;
 4 int n;
 5 int node[maxn]; 
 6 int Prev[maxn];
 7 int Next[maxn];
 8 int cur;
 9 int tot=0;
10 void insert(int a,int b,int s)
11 {
12     cur++;
13     node[cur]=s;
14     Next[a]=cur;
15     Prev[cur]=a;
16     
17     Next[cur]=b;
18     Prev[b]=cur;
19 }
20 void insert_back(int a,int s)
21 {
22     cur++;
23     node[cur]=s;
24     Prev[Next[a]]=cur;
25     Next[cur]=Next[a];
26     
27     Prev[cur]=a;
28     Next[a]=cur;
29 }
30 void insert_front(int b,int s)
31 {
32     cur++;
33     node[cur]=s;
34     Next[Prev[b]]=cur;
35     Prev[cur]=Prev[b];
36     
37     Next[cur]=b;
38     Prev[b]=cur; 
39 }
40 void _delete(int a,int b)
41 {
42     Prev[b]=a;
43     Next[a]=b;
44 }
45 void delete_back(int a)
46 {
47     Prev[Next[Next[a]]]=a;
48     Next[a]=Next[Next[a]];
49 }
50 void delete_front(int b)
51 {
52     Next[Prev[Prev[b]]]=b;
53     Prev[b]=Prev[Prev[b]];
54 }
55 int main()
56 {
57     cin>>n;
58     int tmp;
59     cin>>tmp;
60     insert_back(0,tmp);
61     tot++;
62     for(int i=1;i<n;i++)
63     {
64         cin>>tmp;
65         insert_back(i,tmp);
66         tot++;
67     }
68     tmp=Next[0];
69     while(tmp)
70     {
71         cout<<node[tmp]<<" ";
72         tmp=Next[tmp];
73     }
74     return 0; 
75 }

之后我们要介绍的是链表的指针实现

在程序设计竞赛中不建议使用这种方式,因为在边界处理时往往会访问无效内存

程序竞赛中的链表,应统一使用数组形式,而对于树形结构,具体问题具体分析,怎么方便怎么来

首先是使用指针实现链表的一些注意项

int n;
struct Node
{
    int Data;
    Node *next;
};
Node *head,*rear;

这里节点被封装成了结构体看起来舒服一些

next里存的是下一个节点的地址

head永远指向链表中的第一个元素,这样方便进行操作

rear是当前的操作项,相当于位置变量

然后还是以insert_back函数为例

void insert_back(Node* a,int s)
{
    Node *tmp=new Node();
    tmp->Data=s;
    tmp->next=a->next;
    a->next=tmp;
}

这里的逻辑和之前的数组实现是完全一致的

下面给出单链表的指针实现的完整代码

 1 #include<iostream>
 2 using namespace std;
 3 int n;
 4 struct Node
 5 {
 6     int Data;
 7     Node *next;
 8 };
 9 Node *head,*rear;
10 void insert(Node* a,Node* b,int s)
11 {
12     Node *tmp=new Node();
13     tmp->Data=s;
14     a->next=tmp;
15     tmp->next=b;
16 }
17 void insert_back(Node* a,int s)
18 {
19     Node *tmp=new Node();
20     tmp->Data=s;
21     tmp->next=a->next;
22     a->next=tmp;
23 }
24 void insert_front(Node* b,int s)
25 {
26     Node *tmp=new Node();
27     tmp->next=b;
28     Node *a=head;
29     while(a!=NULL)
30     {
31         if(a->next==b)
32             break;
33         a=a->next;
34     }
35     a->next=tmp;
36 }
37 void _delete(Node* a,Node* b)
38 {
39     delete a->next;
40     a->next=b;
41 }
42 void delete_back(Node* a)
43 {
44     Node *tmp=a->next;
45     a->next=a->next->next;
46     delete tmp;
47 }
48 void delete_front(Node* b)
49 {
50     Node *tmp=head;
51     while(tmp!=NULL)
52     {
53         if(tmp->next==b)
54             break;
55         tmp=tmp->next;
56     }
57     Node *a=head;
58     while(a!=NULL)
59     {
60         if(a->next==tmp)
61             break;
62         a=a->next;
63     }
64     a->next=b;
65     delete tmp;
66 }
67 int main()
68 {
69     cin>>n;
70     head=new Node();
71     int tmp;
72     cin>>tmp;
73     rear=new Node();
74     rear->Data=tmp;
75     head->next=rear;
76     for(int i=1;i<n;i++)
77     {
78         cin>>tmp;
79         insert_back(rear,tmp);
80         rear=rear->next;
81     }
82     rear=head->next;
83     while(rear!=NULL)
84     {
85         cout<<rear->Data<<" ";
86         rear=rear->next;
87     }
88     return 0;
89 }

接下来我们介绍双向链表的指针实现

首先还是给出定义项

int n;
struct Node
{
    int Data;
    Node *prev,*next;
};

区别就是增加了一个prev用来存前驱节点的地址

然后我们给出insert_back函数的定义

void insert_back(Node* a,int s)
{
    Node *tmp=new Node();
    tmp->Data=s;
    
    if(a->next!=NULL)
        a->next->prev=tmp;
    tmp->next=a->next;
    
    tmp->prev=a;
    a->next=tmp;
}

这里的逻辑和之前数组实现基本一致,但是要注意一点那就是一定要考虑好边界情况,在这里就是往链表尾部插入的情况

如果直接是a->next->prev,如果a->next为空,就是访问无效内存,直接会运行错误

所以要加入一个特判

不只在这个地方,在其他的地方也可能出现类似的情况,所以除非有必要,建议不要使用指针形式的链表

下面给出双向链表的指针实现的完整代码

 1 #include<iostream>
 2 using namespace std;
 3 int n;
 4 struct Node
 5 {
 6     int Data;
 7     Node *prev,*next;
 8 };
 9 Node *head,*rear;
10 void insert(Node* a,Node* b,int s)
11 {
12     Node *tmp=new Node();
13     tmp->Data=s;
14     
15     a->next=tmp;
16     tmp->prev=a;
17     
18     tmp->next=b;
19     b->prev=tmp;
20 }
21 void insert_back(Node* a,int s)
22 {
23     Node *tmp=new Node();
24     tmp->Data=s;
25     
26     if(a->next!=NULL)
27         a->next->prev=tmp;
28     tmp->next=a->next;
29     
30     tmp->prev=a;
31     a->next=tmp;
32 }
33 void insert_front(Node* b,int s)
34 {
35     Node *tmp=new Node();
36     tmp->next=b;
37     
38     b->prev->next=tmp;
39     tmp->prev=b->prev;
40     
41     tmp->next=b;
42     b->prev=tmp;
43 }
44 void _delete(Node* a,Node* b)
45 {
46     Node *tmp=a->next;
47     a->next=b;
48     b->prev=a;
49     
50     delete tmp;
51 }
52 void delete_back(Node* a)
53 {
54     Node *tmp=a->next;
55     
56     tmp->next->prev=a;
57     a->next=tmp->next;
58     
59     delete tmp;
60 }
61 void delete_front(Node* b)
62 {
63     Node *tmp=b->prev;
64     
65     tmp->prev->next=b;
66     b->prev=tmp->prev;
67     
68     delete tmp;
69 }
70 int main()
71 {
72     cin>>n;
73     head=new Node();
74     int tmp;
75     cin>>tmp;
76     rear=new Node();
77     rear->Data=tmp;
78     head->next=rear;
79     rear->prev=head; 
80     for(int i=1;i<n;i++)
81     {
82         cin>>tmp;
83         insert_back(rear,tmp);
84         rear=rear->next;
85     }
86     rear=head->next;
87     while(rear!=NULL)
88     {
89         cout<<rear->Data<<" ";
90         rear=rear->next;
91     }
92     return 0;
93 }

所有的程序只测试了一个函数,别的函数实现仅供参考,如有错误欢迎读者指正。

posted @ 2018-07-17 10:08  静听风吟。  阅读(2277)  评论(0编辑  收藏  举报