数据结构第二章——线性表

一、概念及类型定义

1.特点:同一性、有穷性、有序性。

2.基本操作(除第一个以外其他操作初始条件均为线性表L已存在,且要注意有些i的取值范围不能超过L的长度)

InitList(&L) //构造一个空的线性表L

DestroyList(&L) //L已存在,销毁线性表L

ListEmpty(L)//线性表判空 L为空表返回1,反之0
ListLength(L) //返回L中元素个数
PriorElem(L, cur_e, &pre_e) 
//求前驱 cur_e是L的元素且不是第一个,pre_e返回他的前驱

NextElem(L, cur_e, &next_e)
//求后继 cur_e是L的元素且不是最后一个,next_e返回他的后继

GetElem(L, i, &e)
//求某个数据元素;1<= i <= LengthList(L) e返回L中第i个元素的值

LocateElem(L, e)
//定位函数 e给定 返回L中第一个与e相等的元素的位序,不存在返回0

ListTraverse(L, visit())
//遍历 对每个元素调用visit()函数


SortList(&L) 
//排序 按某一数据项的值对线性表中的元素进行排序

ClearList(&L)
//将L置为空表

ListInsert(&L, i, e)
//在L中第i个元素之前插入新的元素e,L长度增加i

ListDelete(&L, i, &e)
//删除L的第i个元素并用e返回其值,L长度减1



二、顺序表示和实现

1.用一组地址连续的存储单元依次存放线性表的各个数据元素。起始地址称为基地址。

2.静态数组定义顺序表:

#define MAXSIZE //数组可能的长度
typedef struct
{
  ElemType elem[MAXSIZE]; //线性表占用的数组空间
  int length; //线性表当前长度
}SqList;

3.动态分配存储空间 :

#define LIST_INIT_SIZE 100 //存储空间的初始分配量
#define LISTINCREMENT 10  //存储空间的分配增量
typedef struct
{
  ElemType *elem  //存储空间基址
  int length;  //当前长度
  int listsize;  //分配的存储容量
}SeqList


//动态分配存储空间的初始化函数 即构造一空表
Status InitList_Sq(SqList &L)
{
  L.elem = (ElemType *) malloc(LIST_INIT_SIZE *sizeof(ElemType));
  if(!L.elem) exit(OVERFLOW);
  L.length = 0;
  L.listsize = LIST_INIT_SIZE;
  return OK;
}//InitList_Sq

4.查找算法

(1)按序号查找:GetData(L, i) = L.elem[i] 查找线性表L中第i个数据元素。

(2)按内容查找:Locate(L, e)

5.插入算法

(1)判断位置是否合法 :1<= i <= n+1

(2)需要从表尾到i逐个一次向右移动数据元素(n-i+1个元素):aj+i = aj j = n, n-1,...,i

(3)插入并修改表的长度 ai = x,n= n+1

Status  ListInsert_Sq(Sqlist  L,int i,ElemType e) 
{  if  (i<1 || i>L.length+1)    return ERROR;
    if   (L.length>=L.listsize)//当前存储空间已满
	{  newbase=(ElemType *) realloc(L.elem, 
          		(L.listsize +LISTINCREMENT)*sizeof(ElemType));
	if (!newbase) exit(OVERFLOW);//分配不成功
	L.elem= newbase;
	L.listsize += LISTINCREMENT;	}
    q=&(L.elem[i-1]);  //q所指向的是第 i 个元素
    for(p=&(L.elem[L.length-1]);p>=q;--p) //从最后一个元素移动
        *(p+1)=*p;
        *q=e;
       ++L.length;
        return OK;
}//ListInsert_Sq

 移动次数:n-i+1

6.删除算法

Status ListDelete_Sq(Sqlist  &L,int i ,ElemType &e)
 {  //在顺序表L中删除第i个元素,并用e返回其值
      //i的合法值为1 <= i <= ListLength_Sq(L)   
   if((i<1) || (i>L.length))    return ERROR;
  	p=&(L.elem[i-1]);
	e=*p;
	q=&(L.elem [ L.length-1]);          
	for(++ p;p<= q;++p)
         *(p-1)=*p;
  	 - - L.length;
	return OK;
  }//ListDelete_Sq     

移动次数:n-1

7.顺序存储结构优缺点

(1)方便存取;无需额外增加存储空间

(2)插入删除移动太多;只能预先静态分配


三、链式表示和实现

1.线性链表

(1)头指针head存放一个地址

每个结点:实际数据+下一个结点的地址

最后一个结点:指针域放一个NULL,链表结束

 (2)单链表存储空间分配和释放:

//头文件:stdlib.h和alloc.h

//malloc函数
void *malloc(unsigned int size);
//free函数
void free(void *p);

LinkList s;//s是指针变量
s = (linklist) malloc(sizeof(LNode))//申请了一个结点空间
free(s)//适当s所指的结点

!!数据域(*s).data 或者s->data
!!指针域(*s).next 或者s->next

(3)单链表初始化: 

//定义单链表
typedef  struct LNode
{ 
  ElemType  data;  //数据域,存储数据元素
  struct LNode * next; 
               //指针域,记录后继结点的存储位置
} LNode, *LinkList;

//初始化单链表
LinkList  init_linklist(LinkList L)   //对带头结点
                                                         单链表进行初始化 
{   
    L=(LinkList)malloc(sizeof(Node)); //申请空间
    L->next=NULL; 		    	 //置为空表     
    return  L;
}

//销毁表DestroyList(L)
void DestroyList(LinkList L)
{	
  LinkList p=L, q=p->next;
  while (q!=NULL)
  {      
    free(p);
	p=q;
    q=p->next;
   }
   free(p);
}

 (4)尾插法建立单链表

void CreateFromTail(LinkList L)
{    LNode *r, *s;    char c;   int  flag=1;     r=L; 
      while(flag)
     {	c=getchar();
	if(c!='$')
	{   s=(LNode*)malloc(sizeof(LNode));
	     s->data=c;	
               r->next=s;  	
               r=s;
	}
	else
	{    flag=0;		
               r->next=NULL;   
          }
    }   
} 

(5)头插法建单链表

void CreateFromHead(LinkList   L)
{    LNode   *s;	char 	c;	int 	flag=1;
      while(flag)
     {	c=getchar();   
	if(c!='$')
	{   s=(LNode*)malloc(sizeof(LNode)); 
               s->data=c;
	     s->next=L->next	
               L->next=s;	}
	else
	     flag=0;
	}
}

 (6)取元素

Status GetElem_L(LinkList L,int i ,ElemType  &e)
{    //L为带头结点的单链表的头指针
	p=L->next; j=1;
	while( p && j<i)
		{
			p=p->next; ++j;
  		}
	if  (!p|| j>i)  return ERROR; //第i个元素不存在
	e = p->data;
	return OK;
}//GetElem_L         //      时间复杂度为O(n)

(7)插入结点:ListInsert(L, i, e)

Status ListInsert_L(LinkList   &L, int   i,  ElemTyp   e ) 
{ //在带头结点的单链表L中第i个位置之前插入元素e
     p=L;j=0;
     while (p && j<i-1)  //当循环结束时p可能指向第i-1个元素
          {
              p=p->next;
              ++j;
           }
    if(!p || j>i-1) return ERROR;
    s=(LinkList ) malloc(sizeof(LNode));  
    s->data=e;   s->next=p->next;    p->next=s;
     return OK;
}//ListInsert_L

 (8)删除结点:ListDelete(L, i, e)

Status ListDelete_L(Linklist &L,  int i,  ElemTyp    &e )
/ /在带头结点单链表 L 上删除第i个结点,并由e返回其值
 {  p=L;j=0;
    while (p->next  && j<i-1 )
     {       
       p=p->next;++j;   
     }
    if(!p->next || j>i-1 ) return ERROR;
    q=p->next;  p->next=q->next;
    e=q->data;    free(q);
   return  OK;
}//ListDelete_L

2.循环链表

表中最后一个结点后继是否为头结点

3.双向链表

每个节点的指针域里包含两个指针,一个指向前驱结点,一个指向后继结点。

4.链表存储的特点

(1)不用事先估计存储规模,但存储密度较低

(2)按序访问时间性能O(n)

(3)操作基于指针


四、一元多项式

见PPT

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值