数据结构 第2章-2线性表的单链表存储结构

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
讨论: 讨论:
对于线性表的单链表存储结 构描述: typedef struct Node { DataType data; struct Node *next; }SLNode, *LinkList; 请注意:typedef不可能创造 请注意:typedef不可能创造 任何新的数据类型, 任何新的数据类型,而仅仅是 在原有的数据类型中命名一个 新名字, 新名字,其目的是使你的程序 更易阅读和移植。 更易阅读和移植。
17
五、循环单链表
循环链表示意图: 循环链表示意图:
2
例: 单链表的建立和输出 例:用单链表结构来存放26个英文字母组成的线 用单链表结构来存放 个英文字母组成的线 性表( , , , , ) 请写出 语言程序。 请写出C语言程序 性表(a,b,c,…,z),请写出 语言程序。
实现思路:先开辟头指针, 实现思路:先开辟头指针,然后陆续为每个结点开辟存储 空间并及时赋值,后继结点的地址要提前送给前面的指针。 空间并及时赋值,后继结点的地址要提前送给前面的指针。
删除动作的核心语句(要借助辅助指针变量q 删除动作的核心语句(要借助辅助指针变量q):
q = p->next; //首先保存 的指针,靠它才能找到c 首先保存b //首先保存b的指针,靠它才能找到c; //将 两结点相连,淘汰b结点; p->next=q->next; //将a、c两结点相连,淘汰b结点; free(q) ; //彻底释放 彻底释放b //彻底释放b结点空间
1
typedef struct student { char name; int age; }student,*pointer; 注意: 同名但不同意。 注意:student和student同名但不同意。同名是为了表述起 和student同名但不同意 来方便。 来方便。 例如,若结构名为student student, 例如,若结构名为student,其新定义名缩写也最好写成 student,因为描述的对象相同,方便阅读和理解。 student,因为描述的对象相同,方便阅读和理解。 是何意? 问2:结构体中间的那个struct Node是何意? 结构体中间的那个struct Node是何意 缩写” SLNode还没出现之前 还没出现之前, 答2:在“缩写” SLNode还没出现之前,只能用原始的 Node来进行变量说明 来进行变量说明。 struct Node来进行变量说明。此处说明了指针分量的数据 类型是struct Node。 类型是struct Node。
9
3、向单链表中插入一个元素
的示意图如下: 在链表中插入一个元素X 的示意图如下: p a b 插 入 X p a b
p->next
q
X
s->next
链表插入的核心语句: 链表插入的核心语句: 1: >next=p >next; Step 1:q->next=p->next; 2: >next=q Step 2:p->next=q ;
16
for(i = 0; i < ListLength(head); i++) { if(ListGet(head, i, &x) == 0) printf("错误 错误! { printf("错误! \n"); return; } else printf("%d ", x); } Destroy(&head); }
13
三、单链表的操作效率分析
时间效率分析 (1) 查找 ) 因线性链表只能顺序存取,即在查找时要从头指针找起, 因线性链表只能顺序存取,即在查找时要从头指针找起, 查找的时间复杂度为 O(n)。 。 (2) 插入和删除 ) 因线性链表不需要移动元素,只要修改指针, 因线性链表不需要移动元素,只要修改指针,仅就插入或删 除而言, 除而言,时间复杂度为 O(1)。 。 但是,如果要在单链表中进行在某结点前插或删除操作, 但是,如果要在单链表中进行在某结点前插或删除操作, 因为要从头查找前驱结点,所以一般情况下, 因为要从头查找前驱结点,所以一般情况下,单链表插 从头查找前驱结点 入和删除操作的时间复杂度是 入和删除操作的时间复杂度是 O(n)(同顺序表)。 (同顺序表)。
8
2、求单链表中数据元素的个数 int ListLength(SLNode *head) { /*p指向头结点 指向头结点* SLNode *p = head; /*p指向头结点*/ /*size初始为 初始为0*/ int size = 0; /*size初始为0*/ while(p->next != NULL) /*循环计数*/ while(p/*循环计数* 循环计数 { pp = p->next; size ++; } return size; }
(3)
pq->next = p->next; p->next = q; (4) return 1; } 注:此单链表是带头结点的
11
4、从 单链表中删除一个元素
在链表中删除某元素b的示意图如下: 在链表中删除某元素b的示意图如下: p a × b × c
p->next
q
(p->next) -> next
X 结点的生成方式: 结点的生成方式:
m=sizeof(SLNode); m= q=(SLNode *)malloc(m);
q->data=X ; 思考:Step1和 能互换么? 思考:Step1和2能互换么? q->next= ?
10
int ListInsert(SLNode *head, int i, DataType x) { SLNode *p, *q; int j; p = head; j = -1;
思考: 省略free(q)语句行不行? 语句行不行 思考: 省略 语句行不行?
12
int ListDelete(SLNode *head, int i, DataType *x) { SLNode *p, *s; int j; (1) p = head; j = -1; while(pp->nextwhile(p->next != NULL && p->next->next!= NULL && j < i - 1) { p = p->next; pj++; } if(j != i - 1) printf(“插入位置参数错 插入位置参数错! { printf( 插入位置参数错!”); return 0; } p(2) s = p->next; s*x = s->data; (3) p->next = p->next->next; p->nextfree(s); return 1; }
int m=sizeof(node); /*结构类型定义好之后,每个node类型的长 /*结构类型定义好之后 每个node 结构类型定义好之后, node类型的长 度就固定了, 求一次即可* 度就固定了,m求一次即可*/
4
void build( ) //字母链表的生成。要一个个慢慢链入 { int i; head=(node*)malloc(m); //m=sizeof(node) 前面已求出 p=head; for( i=1; i<26; i++) //因尾结点要特殊处理,故i≠26 因尾结点要特殊处理, 因尾结点要特殊处理 { p->data=i+‘a’-1; // 第一个结点值为字符 第一个结点值为字符a p->next=(node*)malloc(m); //为后继结点“挖坑”! //为后继结点 挖坑” 为后继结点“ p=p->next;} //让指针变量 指向后一个结点 让指针变量P指向后一个结点 ; 让指针变量 p->data=i+‘a’-1; //最后一个元素要单独处理 最后一个元素要单独处理 p->next=NULL ;} //单链表尾结点的指针域要置空! /单链表尾结点的指针域要置空!
14
四、应用举例
重点是链表
例1、编程实现:建立一个单链表,首先依次输入数 据元素1,2,…,10,然后删除数据元素5,最后依次 显示当前表中的数据元素。 #include <stdio.h> #include <stdlib.h> #include <malloc.h> typedef int DataType; #include "LinList.h"
6
void main( ) { build( ); display( ); } 上述建立的单链表带头结点吗? 问:上述建立的单链表带头结点吗?
7
二、单链表的操作实现
定义单链表结点的结构体如下: 定义单链表结点的结构体如下: typedef struct Node { DataType data; struct Node *next; }SLNode; 1、初始化 void ListInitiate(SLNode **head) /*初始化*/ { /*如果有内存空间,申请头结点空间并使头指针head指向头 结点*/ if((*head = (SLNode *)malloc(sizeof(SLNode))) == NULL) exit(1); (*head)->next = NULL; /*置链尾标记NULL */ }
先挖“ 后种“ 先挖“坑”,后种“萝 卜”!
3
将全局变量及函数提前说明: 将全局变量及函数提前说明: #include<stdio. #include<stdio.h> #include<stdlib. #include<stdlib.h> typedef struct node{ char data; struct node *next; }node; node *p,*q,*head; int n ; //一般需要3 //一般需要3个指针变量 一般需要 // 数据元素的个数
新手特别容易忘记!! 新手特别容易忘记!!
5
void display()
/*字母链表的输出 字母链表的输出*/ 字母链来自百度文库的输出
{p=head; sum=0; while (p) //当指针不空时循环(仅限于无头结点的情况) //当指针不空时循环 仅限于无头结点的情况) 当指针不空时循环( 无头结点的情况 {printf("%c",p->data); p=p->next; //让指针不断 顺藤摸瓜” 让指针不断“ //让指针不断“顺藤摸瓜” } sum++; } 讨论:要统计链表中数据元素的个数,该如何改写? 讨论:要统计链表中数据元素的个数,该如何改写?
问1:第一行的Node 与最后一行的SLNode是不是一回事? 第一行的Node 与最后一行的SLNode是不是一回事? SLNode是不是一回事 答1:不是。前者Node是结构名,后者SLNode是对整个 不是。前者Node是结构名,后者SLNode是对整个 Node是结构名 SLNode struct类型的一种“缩写”,是一种“新定义名”,它只 struct类型的一种“缩写” 是一种“新定义名” 类型的一种 是对现有类型名的补充,而不是取代。 是对现有类型名的补充,而不是取代。
15
void main(void) SLNode *head; { int i , x; ListInitiate(&head); for(i=0;i<10;i++){ if(ListInsert(head, i, i+1) == 0) printf("错误 错误! { printf("错误! \n"); return; } } if(ListDelete(head, 4, &x) == 0) { printf("错误 错误! printf("错误! \n"); return; }
while(pwhile(p->next != NULL && j < i - 1) { (1) pp = p->next; if(j != i - 1){ printf("插入位置参数错!"); printf("插入位置参数错! 插入位置参数错 (2) return 0; } j++; }
if((q = (SLNode *)malloc(sizeof(SLNode))) == NULL) exit(1); q->data = x;
相关文档
最新文档