《大话数据结构》第三章知识点下

线性表

线性表的链式存储结构
  1. 定义:
    在这里插入图片描述
    我们把链表中第一个结点的存储位置叫做头指针,单链表的第一个结点前附设一个结点,叫头结点(如图):
    在这里插入图片描述
    在这里插入图片描述
  2. 头指针与头结点的异同

在这里插入图片描述

  1. 单链表的读取
    获得链表第 i 个数据的算法思路:
    • 声明一个结点p指向第一个结点,初始化 j 从1开始;
    • 当 j 小于1 时,就遍历链表,让 p 的指针向后移动,不断指向下一结点,j 累加1;
    • 若到链表末尾p 为空,则说明第 i 个元素不存在;
    • 否则查找成功,返回结点 p 的数据;
      代码如下:
/*初始条件 : 顺序链表L 已经存在,1 <= i <= ListLength(L)*/
/*操作结果 :用e 返回L 中第 i 个数据元素的值 */
Staus GetElm (LinkList L, int i, ElemType *e){
	int  j;
	LinkList p;                         //声明一结点p
	p = L->next;                    //让p指向链表L的第一个结点
	j  = 1;                             // j 为计数器 
	while(p && j < 1){            //p 不为空或计数器还没有等于 i 时,循环继续
		p = p->next;                 //指向下一个结点
		++j;
	}
	if ( !p || j > i)
		return ERROR;           //第 i 个元素不存在
	*e = p ->data;                   //取第 i 个元素的数据
	return OK;
}
  1. 单链表的插入与删除
    单链表第 i 个数据插入结点的算法思路
    • 声明一结点p 指向链表第一个结点,初始化j 从1 开始;
    • 当 j 小于 1 时,就遍历链表,让p的指针向后移动,不断指向下一结点,j 累加 1;
    • 若到链表末尾p 为空,则说明第 i 个元素不存在;
    • 否则查找成功,在系统中生成一个空结点 s;
    • 将数据元素e 赋值给 s -> data;
    • 单链表的插入标准语句 s->next = p->next;p->next = s;
    • 返回成功
      实现代码算法如下:
/*初始条件 : 顺序链表L 已经存在,1 <= i <= ListLength(L)*/
/*操作结果 :在L 中第 i 个位置之前插入新的数据元素e ,L的长度加 1 */
Staus GetElm (LinkList *L, int i, ElemType e){
	int j;
	LinkList p, s;
	j = 1;
	while (p && j < i){                          //寻找第 i 个结点
		p = p -> next;
		++j;
	}
	if( !p || j >i)
		return ERROR;                        //第 i 个元素不存在
	s = (LinkLinst)malloc(sizeof(Node));        //生成新结点;
	s -> data = e;
	s  -> next = p ->next;                //将 p的后继结点赋值给 s 的后继
	p -> next =  s;                          //将 s 赋值给 p 的后继
	return OK;
}

单链表第 i 个数据删除结点的算法思路

  • 声明一结点p 指向链表第一个结点,初始化j 从1 开始;
  • 当 j 小于 1 时,就遍历链表,让p的指针向后移动,不断指向下一结点,j 累加 1;
  • 若到链表末尾p 为空,则说明第 i 个元素不存在;
  • 否则查找成功,将欲删除的结点 p -> next 赋值给 q ;
  • 单链表的删除标准语句 p -> next = q ->next;
  • 将q结点中的数据赋值给 e ,并作为返回;
  • 释放q结点;
  • 返回成功
    实现代码算法如下:
/*初始条件 : 顺序链表L 已经存在,1 <= i <= ListLength(L)*/
/*操作结果 :在L 中第 i 个位置之前插入新的数据元素e ,L的长度加 1 */
Staus GetElm (LinkList *L, int i, ElemType *e){
	int j;
	LinkList p, s;
	j = 1;
	while (p && j < i){                          //寻找第 i 个结点
		p = p -> next;
		++j;
	}
	if( !p || j >i)
		return ERROR;                        //第 i 个元素不存在
	q = p -> next;                               
	p -> next = q -> next;                     //将q 的后继赋值给 p 的后继
	*e = q -> next;                                //将q 的数据结点给数据 *e;
	free(q);                                              //释放内存
	return OK;
}
  1. 单链表的整表创建
    单链表的整表创建的算法思路

    • 声明一结点 p 和 计数器变量 j;
    • 初始化一空链表L
    • 让L的头结点的指针指向NULl,即建立一个带头结点的单链表;
    • 循环:
      • 生成一新结点赋值给p;
      • 随机一串数字赋值给 p的数据域 p-> data;
      • 将 p插入到头结点与之前一新结点之前
        代码如下:
      /* 随机产生n个元素的值,建立带头结点的单链表(头插法)*/
      void CreateListHead ( LinkList *L, int n){
      	LinkList p;
      	int i;
      	srand(time(0);                             //初始化随机种子
      	*L = (LinkList)malloc(sizeof(Node));                 
      	(*L) -> next = NULL;                       //先建立一个带头接点的单链表
      	for (i = 0; i < n; i++){
      	p =(LinkList)malloc(sizeof(Node));            //生成新结点
      	p -> data = rand()%100 + 1;                      //随机产生100以内的数字
      	p ->next = (*L) ->next;
      	(*L) ->next = p;                                         //插到表头
      	}
      

    }
    ```

     	```
     			/* 随机产生n个元素的值,建立带头结点的单链表(尾插法)*/
     	void CreateListHead ( LinkList *L, int n){
     		LinkList p,r;
     		int i;
     		srand(time(0);                             //初始化随机种子
     		*L = (LinkList)malloc(sizeof(Node));                 
     		r = *L;                                          //r为指向尾部的指针
     		for (i = 0; i < n; i++){
     			p =(LinkList)malloc(sizeof(Node));            //生成新结点
     			p -> data = rand()%100 + 1;                      //随机产生100以内的数字
     			r -> next = p;                                        //将表尾终端结点的指针指向新结点
     			r = p;                                         //将当前的新结点定义为表尾终端结点
     		}
     		r -> next = NULLl;
     }
     	```
    
  2. 单链表的整表删除
    单链表的整表删除算法思路:

    • 声明一结点 p 和 q;
    • 将第一个结点赋值给 p;
    • 循环:
      • 将下一结点赋值给q;
      • 释放p;
      • 将q 赋值给 p;
        代码如下
    /* 初始条件 :顺序线性表L 已经存在,操作结果 :将 L充值为空表*/
    Status ClearList(LinkList *L){
      LinkList p, q;
      p = (* L) -> next;                    //p指向第一个结点
      while (p){                              //直到表尾
      	q = p -> next;
      	free(p);
      	p = q;
      }
      (*L) -> next = NULL;                     //头结点指针域为空
      return OK;
    }
    
  3. 单链表结构与顺序储存结构优缺点
    在这里插入图片描述

  4. 静态链表
    线性表的静态链表存储结构代码如下:

    	#define MAXSIZE 1000           //假设静态链表最大长度为1000
    	typedef struct{
    		ElemType data;
    		int cur                              //游标(Cursor),为0时表示无指向;
    	}Component,StaticLinkList[MAXSIZE];
    

    静态链表的插入:
    在这里插入图片描述

    /*若备用空间链表非空,则返回分配的结点下标,否则返回0*/
    int Malloc_SLL(StaticLinkList space){
    	int i = space[0].cur;
    	if(space[0].cur){
    		space[0].cur = space[i].cur;
    	return i;
    	}
    }
    

    插入代码:

    /* 在 L 中第 i 个元素之前插入新的数据元素 e*/
    Status LinstInsert(StatucLinkList L, int i, ElemType e){
    	int j, k, l;
    	k = MAX_SIZE - 1;                                                         //注意 k 首先是最后一个元素的下标 
    	if(i < 1 || i > ListLength(L) + 1)
    		return ERROR;
    	j = Malloc_SLL(L);                                                     //获得空间分量的下标
    	if(j){
    		L[j].data = e;                                                   //将数据赋值给此分量的data;
    		for(l = i; l <= i - 1; l++)                                     //找到第 i 个元素之前的位置;
    			k = L[k].cur;
    		L[j].cur = L[k].cur;                                          //把第 i 个元素之前的cur赋值给新的cur;
    		L[K].cur = j;                                                //把新元素的下标赋值给第 i 个元素之前的cur
    		return OK;
    	}
    	return ERROR;
    }
    

    静态链表的删除
    备用代码 :

    	/*将下标为 k 的空闲结点回收到备用链表*/
    	void Free_SSL(StaticLinkList space, int k){
    		space[k].cur = space[0].cur;                    //把第一个元素cur 值赋给要删除的分量cur;
    		space[0].cur = k;                              //把要删除的分量下标赋值给第一个元素的cur;
    	}
    

    删除代码如下:

    		/*删除在L 中第 i 个数据元素 e*/
    		Status LinstInsert(StatucLinkList L, int i){
    			int j, k;
    			if(i < 1 || i > ListLength(L) + 1)
    				return ERROR;
    			k = MAX_SIZE - 1;                                                      
    			for( j = 1; j <= i - 1; j++)
    				k = L[k].cur;
    			j = L[k].cur;
    			L[K].cur = L[j].cur;
    			Free_SSL(L,j);
    			return OK;
    		}	
    

    静态链表的优缺点:
    在这里插入图片描述

  5. 循环链表
    定义:将链表中终端结点的指针端有由空指针改为指向头结点的,就使整个单链表形成一个环。
    在这里插入图片描述
    不用头指针,而是用指向终端结点的尾指针表示循环链表,便于查找开始结点和终端结点在这里插入图片描述
    将两个循环链表合并成一个表(尾指针分别为:rearA,rearB):
    在这里插入图片描述代码如下:

    	p = rearA -> next;                         //保存A表的头结点
    	rearA -> next = rearB -> next ->next;     //将本是指向B表的第一个结点赋值给rearA -> next;
    	rearB ->next = p;                        //将A表的头结点赋值给rearB -> next;
    	free(p);                                //释放p;
    

10.双向链表

  1. 定义:双向链表是在单链表的每个结点中,在设置一个指向其前驱结点的指针域 .

  2. 双向链表的储存结构:

    typedef struct{
    	ElemType data;
    	struct DuLNode *prior;          //直接前驱指针;
    	struct DuLNode *bext;          //直接后继指针;
    }DulNode, *DuLinkList;
    
  3. 插入
    在这里插入图片描述

  4. 删除
    在这里插入图片描述
    代码如下:

    p -> prior -> next = p -> next;        //把p -> next 赋值给p -> prior 的后继 ;
    p -> next -> prior = p -> prior;      //把p -> prior 赋值给 p -> next 的前驱;
    free(p);                             //释放结点
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值