数据结构学习笔记01链表

一.单向链表:

由于线性表的顺序存储结构(数组),在插入和删除需要移动大量元素以及其他特殊情况下,效率低下,耗时费力,此处引入了链表的概念。

链表的基本组成单元为结点(node),包括两个域:存储数据元素信息的域->数据域;存储直接后继存储位置的域(指针)->指针域。

 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <time.h>
  4 #define OK 1
  5 #define ERROR 0
  6 
  7 
  8 typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
  9 typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */
 10 
 11 typedef struct Node
 12 {
 13     ElemType data;
 14     struct Node *next;
 15 }Node;
 16 typedef struct Node *LinkList; //定义LinkList
 17 
 18 Status InitList(LinkList *L);
 19 Status Destroy(LinkList L);
 20 Status ClearList(LinkList *L);
 21 bool ListEmpty(LinkList L); 
 22 int ListLength(LinkList L);
 23 Status GetElem(LinkList L,int i,ElemType *e);
 24 int LocateElem(LinkList L,ElemType e);
 25 Status PriorElem(LinkList *L, ElemType cur_e, LinkList *pre_e);
 26 Status NextElem(LinkList *L, ElemType cur_e, LinkList *next_e);
 27 Status ListInsert(LinkList *L,int i,ElemType e);
 28 Status ListDelete(LinkList *L,int i,ElemType *e);
 29 Status ListTraverse(LinkList L);
 30 void CreateListHead(LinkList *L, int n);
 31 void CreateListTail(LinkList *L, int n);
 32 
 33 Status visit(ElemType c)
 34 {
 35     printf("%d ",c);
 36     return OK;
 37 }
 38 
 39 /*初始化顺序线性表: 构造一个空的线性表L*/
 40 Status InitList(LinkList *L) 
 41 { 
 42     *L = (LinkList)malloc(sizeof(Node)); /* 产生头结点,并使L指向此头结点,L为头指针 */
 43     if(!(*L)) /* 存储分配失败 */
 44             return ERROR;
 45     (*L)->next = NULL; /* 指针域为空 */
 46 
 47     return OK;
 48 }
 49 /*初始条件:线性表L已存在。操作结果:销毁线性表L*/
 50 Status Destroy(LinkList L)
 51 {
 52     ClearList(&L);
 53     free(L);
 54     L = NULL;
 55 }
 56 
 57 /* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
 58 Status ClearList(LinkList *L)
 59 { 
 60     LinkList p,q;
 61     p=(*L)->next;           /*  p指向第一个结点 */
 62     while(p)                /*  没到表尾 */
 63     {
 64         q=p->next;
 65         free(p);
 66         p=q;
 67     }
 68     (*L)->next = NULL;        /* 头结点指针域为空 */
 69     return OK;
 70 }
 71 
 72 /* 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
 73 bool ListEmpty(LinkList L)
 74 { 
 75     if(L->next)
 76         return false;
 77     else
 78         return true;
 79 }
 80 
 81 /* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
 82 int ListLength(LinkList L)
 83 {
 84     int i = 0;
 85     LinkList p=L->next; /* p指向第一个结点 */
 86     while(p)                        
 87     {
 88         i++;
 89         p=p->next;
 90     }
 91     return i;
 92 }
 93 
 94 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) 
 95 操作结果:用e返回L中第i个数据元素的值 */
 96 Status GetElem(LinkList L,int i,ElemType *e)
 97 {
 98     int j = 1;             /* j为计数器 */
 99     LinkList p;             /* 声明一结点p */
100     p = L->next;         /* 让p指向链表L的第一个结点 */          
101     while (p && j < i) {   /* p不为空或者计数器j还没有等于i时,循环继续 */  
102         p = p->next;       /* 让p指向下一个结点 */
103         j++;
104     }
105     if ( !p || j>i ) 
106         return ERROR;       /*  第i个元素不存在 */
107     *e = p->data;        /*取第i个元素的数据 */
108     return OK;
109 }
110 
111 /* 初始条件:顺序线性表L已存在 
112 操作结果:返回L中第1个与e满足关系的数据元素的位序。
113 若这样的数据元素不存在,则返回值为0 */
114 int LocateElem(LinkList L,ElemType e)
115 {
116     int i=0;
117     LinkList p=L->next;
118     while(p)
119     {
120         i++;
121         if(p->data==e) /* 找到这样的数据元素 */
122                 return i;
123         p=p->next;
124     }
125 
126     return 0;
127 }
128 
129 /*初始条件:线性表L已存在
130 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,
131 否则操作失败,pre_e无定义*/
132 Status PriorElem(LinkList *L, ElemType cur_e, LinkList *pre_e)
133 {
134     LinkList p;
135     p = (*L)->next;
136     if(p->data == cur_e) {        /* 是第一个 */
137         pre_e = NULL;
138         return ERROR;
139     }
140     while(p->next)
141     {
142         if(p->next->data == cur_e) {
143             *pre_e = p;
144             return OK;
145         }
146         p = p->next;
147     }
148     pre_e = NULL;
149     return ERROR;
150 }
151 
152 /*初始条件:线性表L已存在
153 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后驱,
154 否则操作失败,next_e无定义*/
155 Status NextElem(LinkList *L, ElemType cur_e, LinkList *next_e)
156 {
157     LinkList p;
158     p = (*L);
159     while(p->next) 
160     {
161         if(p->data == cur_e) {
162             *next_e = p->next;
163             return OK;
164         }
165         p = p->next;
166     } 
167     *next_e = NULL;
168     return ERROR;
169 }
170 
171 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) + 1,
172 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
173 Status ListInsert(LinkList *L,int i,ElemType e)
174 { 
175     int j = 1;
176     LinkList p,s;
177     p = *L;  
178     while (p && j < i) {    /* 寻找第i个结点 */
179         p = p->next;
180         ++j;
181     } 
182     if (!p || j > i) 
183         return ERROR;   /* 第i个元素不存在 */
184     s = (LinkList)malloc(sizeof(Node));  /*  生成新结点(C语言标准函数) */
185     s->data = e;  
186     s->next = p->next;      /* 将p的后继结点赋值给s的后继  */
187     p->next = s;          /* 将s赋值给p的后继 */
188     return OK;
189 }
190 
191 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)
192 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
193 Status ListDelete(LinkList *L,int i,ElemType *e) 
194 { 
195     int j;
196     LinkList p,q;
197     p = *L;
198     j = 1;
199     while (p->next && j < i) {    /* 遍历寻找第i个元素 */
200         p = p->next;
201         ++j;
202     }
203     if (!(p->next) || j > i) 
204         return ERROR;           /* 第i个元素不存在 */
205     q = p->next;
206     p->next = q->next;            /* 将q的后继赋值给p的后继 */
207     *e = q->data;               /* 将q结点中的数据给e */
208     free(q);                    /* 让系统回收此结点,释放内存 */
209     return OK;
210 }
211 
212 /* 初始条件:顺序线性表L已存在
213 操作结果:依次对L的每个数据元素输出 */
214 Status ListTraverse(LinkList L)
215 {
216     LinkList p=L->next;
217     while(p)
218     {
219         visit(p->data);
220         p=p->next;
221     }
222     printf("\n");
223     return OK;
224 }
225 
226 /*  随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
227 void CreateListHead(LinkList *L, int n) 
228 {
229     LinkList p;
230     int i;
231     srand(time(0));                         /* 初始化随机数种子 */
232     *L = (LinkList)malloc(sizeof(Node));
233     (*L)->next = NULL;                      /*  先建立一个带头结点的单链表 */
234     for (i=0; i<n; i++) 
235     {
236         p = (LinkList)malloc(sizeof(Node)); /*  生成新结点 */
237         p->data = rand()%100+1;             /*  随机生成100以内的数字 */
238         p->next = (*L)->next;    
239         (*L)->next = p;                        /*  插入到表头 */
240     }
241 }
242 
243 /*建立带表头结点的单链线性表L(尾插法) */
244 void CreateListTail(LinkList *L, int n) 
245 {
246     LinkList p,r;
247     *L = (LinkList)malloc(sizeof(Node));     /* L为整个线性表 */
248     r = *L;                              /* r为指向尾部的结点 */
249     for (int i = 0; i < n; i++) {
250         p = (Node *)malloc(sizeof(Node));      /*  生成新结点 */
251         scanf("%d",p->data); 
252         r->next = p;        /* 将表尾终端结点的指针指向新结点 */
253         r = p;            /* 将当前的新结点定义为表尾终端结点 */
254     }
255     r->next = NULL;                       /* 表示当前链表结束 */
256 }
257 int main()
258 {
259     LinkList L, pre_e,next_e;    //创建一个可以指向结点的指针 
260     CreateListTail(&L,10);
261     ListInsert(&L,11,55); 
262     ListTraverse(L);
263     PriorElem(&L, 3, &pre_e);
264     NextElem(&L, 3, &next_e);
265     printf("前驱%d\n",(*pre_e).data);
266     printf("后继%d\n",(*next_e).data);
267     Destroy(L);
268 
269         
270     return 0;
271 } 
sj1_0

单向链表的基本结构:

typedef struct Node

{

    ElemType data;

    struct Node *next;

}Node;

typedef struct Node *LinkList; //定义LinkList

单向链表的基本操作:/*只需浏览,作了解,详见(代码:sj1_0)*/

Status InitList(LinkList *L);

       操作结果:构造一个空的线性表。

Status Destroy(LinkList L);

       初始条件:线性表L已存在。

       操作结果:销毁线性表L

Status ClearList(LinkList *L);

       初始条件:线性表L已存在。

    操作结果:将L重置为空表

Status ListEmpty(LinkList L);      

       初始条件:线性表L已存在。

       操作结果:若L为空表,则返回TRUE,否则返回FALSE。

int ListLength(LinkList L);

    初始条件:线性表L已存在。

    作结果:返回L中数据元素个数。

Status GetElem(LinkList L, int i, ElemType *e);

       初始条件:顺序线性表L已存在,1≤i≤ListLength(L)。

       操作结果:用e返回L中第i个数据元素的值。

int LocateElem(LinkList L, ElemType e);

       初始条件:顺序线性表L已存在。

       操作结果:返回L中第1个与e满足关系的数据元素的位序。

若这样的数据元素不存在,则返回值为0。

Status PriorElem(LinkList *L, ElemType cur_e, LinkList *pre_e);

       初始条件:线性表L已存在

    操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,

    否则操作失败,pre_e无定义。

Status NextElem(LinkList *L, ElemType cur_e, LinkList *next_e);

       初始条件:线性表L已存在

    操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后驱,

    否则操作失败,next_e无定义。

Status ListInsert(LinkList *L, int i, ElemType e);

       初始条件:顺序线性表L已存在,1 ≤i ≤ ListLength(L) + 1。

    操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1。

Status ListDelete(LinkList *L, int i, ElemType *e);

       初始条件:顺序线性表L已存在,1≤i≤ListLength(L)。

    操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1。

Status ListTraverse(LinkList L);

       初始条件:顺序线性表L已存在。

    操作结果:依次对L的每个数据元素输出。

void CreateListHead(LinkList *L, int n);

       操作结果:立带表头结点的单链线性表L(头插法)。

void CreateListTail(LinkList *L, int n);

       操作结果:建立带表头结点的单链线性表L(尾插法)。

 

1.单链表的读取

  算法思路:

  1.声明一个指正p指向链表的第一个结点,初始化j = 1。

  2.当j<i时,遍历链表,p=p->next; j++;

  3.若链表末尾p为空,则说明第i个结点不存在。

  4.否则查找成功,返回结点p的数据。

 

 1 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) 
 2 操作结果:用e返回L中第i个数据元素的值 */
 3 Status GetElem(LinkList L,int i,ElemType *e)
 4 {
 5     int j = 1;             /* j为计数器 */
 6     LinkList p;             /* 声明一结点p */
 7     p = L->next;         /* 让p指向链表L的第一个结点 */          
 8     while (p && j < i) {   /* p不为空或者计数器j还没有等于i时,循环继续 */  
 9         p = p->next;       /* 让p指向下一个结点 */
10         j++;
11     }
12     if ( !p || j>i ) 
13         return ERROR;       /*  第i个元素不存在 */
14     *e = p->data;        /*取第i个元素的数据 */
15     return OK;
16 }
View Code

 

2.单链表的插入

 

  算法思路:

  1.声明一个指针p指向链表头结点,向后遍历p=p->next,直到满足条件。

  2.新建一个结点s。

  3.s->next = p->next ①

  4.p->next = s       ②③

 1 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) + 1,
 2 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
 3 Status ListInsert(LinkList *L,int i,ElemType e)
 4 { 
 5     int j = 1;
 6     LinkList p,s;
 7     p = *L;  
 8     while (p && j < i) {    /* 寻找第i个结点 */
 9         p = p->next;
10         ++j;
11     } 
12     if (!p || j > i) 
13         return ERROR;       /* 第i个元素不存在 */
14     s = (LinkList)malloc(sizeof(Node));  /*  生成新结点 */
15     s->data = e;  
16     s->next = p->next;      /* 将p的后继结点赋值给s的后继  */
17     p->next = s;            /* 将s赋值给p的后继 */
18     return OK;
19 }
View Code

 

3.单链表的删除

 

  算法思路:

  1. 声明一个指针p指向链表头结点,向后遍历p=p->next,直到满足条件。

  2. q = p->next

  3. p->next = q->next  ①②

  4. free(q)                ③④

 1 /* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)
 2 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
 3 Status ListDelete(LinkList *L,int i,ElemType *e) 
 4 { 
 5     int j;
 6     LinkList p,q;
 7     p = *L;
 8     j = 1;
 9     while (p->next && j < i) {    /* 遍历寻找第i个元素 */
10         p = p->next;
11         ++j;
12     }
13     if (!(p->next) || j > i) 
14         return ERROR;           /* 第i个元素不存在 */
15     q = p->next;
16     p->next = q->next;            /* 将q的后继赋值给p的后继 */
17     *e = q->data;               /* 将q结点中的数据给e */
18     free(q);                    /* 让系统回收此结点,释放内存 */
19     return OK;
20 }
View Code

 

4.单链表的整体创建

  算法思路:

  1.创建指向头结点的头指针L,使r=L

  While(){

    2.新建结点p

    3.r->next = p

    4.r = p

  }如此往复

  5.最后一个结点指针指向NULL

 1 /*建立带表头结点的单链线性表L(尾插法) */
 2 void CreateListTail(LinkList *L, int n) 
 3 {
 4     LinkList p,r;
 5     *L = (LinkList)malloc(sizeof(Node));     /* L为整个线性表 */
 6     r = *L;                              /* r为指向尾部的结点 */
 7     for (int i = 0; i < n; i++) {
 8         p = (Node *)malloc(sizeof(Node));      /*  生成新结点 */
 9         scanf("%d",p->data); 
10         r->next = p;        /* 将表尾终端结点的指针指向新结点 */
11         r = p;            /* 将当前的新结点定义为表尾终端结点 */
12     }
13     r->next = NULL;                       /* 表示当前链表结束 */
14 }
View Code

总体思路就是如此。理解模型后,其他操作原理相同。

practice:

1.已知线性表中的元素以值的递增有序排列,并以单链表做存储结构。试写一高效的算法,删除表中所有大于mink且小于maxk的元素(若表中存在这样德尔元素),同时释放被删结点空间,并分析你的算法复杂度(注意:mink 和 maxk 是给定的两个参变量,它们的值可以和表中元素相同,也可以不同)。代码(代码:sj1_1)

 1 //可以追溯到短学期写的
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 struct line
 6 {
 7     int num;
 8     struct line *next;
 9 };
10 typedef struct line *LinkList;
11 LinkList head;
12 
13 struct line *creat();
14 struct line *cut(int min,int max);
15 void display();
16 int main()
17 {
18     int mink,maxk;
19     creat();
20     display();
21     printf("Plead input mink & maxk:");
22     scanf("%d %d",&mink,&maxk);
23     cut(mink,maxk);
24     display();
25     return 0;
26 } 
27 
28 struct line *creat()
29 {
30     LinkList p1, p2;
31     int count;
32     printf("Please input the number of JieDian:");
33     scanf("%d",&count);
34     p1 = p2 =(struct line *)malloc(sizeof(struct line));
35     scanf("%d",&p1->num);
36     head = p1;
37     for(int i = 1;i < count;i++)
38     {
39         p2 =(struct line *)malloc(sizeof(struct line));
40         scanf("%d",&p2->num);
41         p1->next = p2;
42         p1 = p2;
43     }
44     p2->next = NULL;
45     return head;
46 }
47 struct line *cut(int min,int max)
48 {
49     LinkList p, q;
50     p = head;
51     while(p->next->num <= min)
52         p = p->next;
53     while(p->next->num > min && p->next->num < max)
54     {
55         q = p->next;
56         p->next = q->next ;
57         free(q);
58     }
59     q = NULL;    //    free(q)只是释放了q所指的内存空间。     q = NULL防止发生q为野指针 
60     return head;
61 }
62 
63 void display()
64 {
65     LinkList p;
66     p = head;
67     if(p == NULL)
68         printf("NULL!");
69     else
70     {
71         while(p != NULL)
72         {
73             printf("%d ",p->num);
74             p = p->next; 
75         }
76     }
77     printf("\n");
78 }
sj1_1

2.试写一算法,实现顺序表的就地置逆(不开辟新空间),即利用原表的存储空间将线性表(a1,a2,…,an)逆置为(an,an-1,…,a1).

3.试写一算法,对单链表实现就地置逆。(代码:sj1_2)

 1 /*短学期写的。。。 
 2 单链表就地逆置(不开辟新空间) Change()
 3 头结点不存num数据*/
 4 #include <stdio.h>
 5 #include <stdlib.h>
 6 
 7 struct line
 8 {
 9     int num;
10     struct line* next;
11 };
12 struct line *head;
13 struct line *creat();
14 void Change();
15 void display();
16 int main()
17 {
18     creat();
19     printf("Original data:");
20     display();
21     Change();
22     printf("Changed  data:");
23     display();
24 }
25 
26 struct line *creat()
27 {
28     struct line *p1,*p2;
29     int count;
30     printf("Please input the number of JieDian:");
31     scanf("%d",&count);
32     p1 = p2 = (struct line *)malloc(sizeof(struct line));
33     p1->num = 0;
34     head = p1;
35     for(int i = 0;i < count;i++)
36     {
37         p2 = (struct line *)malloc(sizeof(struct line));
38         scanf("%d",&p2->num);
39         p1->next = p2;
40         p1 = p2;
41     }
42     p2->next = NULL;
43     return head;
44 }
45 void Change()
46 {
47     struct line *p,*q;
48     p = head->next;
49     head->next = NULL;
50     while(p != NULL)
51     {
52         q = p->next;
53         p->next = head->next;
54         head->next = p;
55         p = q;
56     }
57 }
58 void display()
59 {
60     struct line *p;
61     p = head->next;
62     if(p == NULL)
63         printf("NULL!");
64     else
65     {
66         while(p != NULL)
67         {
68             printf("%d ",p->num);
69             p = p->next; 
70         }
71     }
72     printf("\n");
73 }
sj1_2

 

二.双向链表(做保留)

三.循环链表(做保留)

转载于:https://www.cnblogs.com/kuotian/p/5302335.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值