《数据结构C语言版》第二章线性表知识点

顺序表的操作

这一部分比较简单,相信只要系统学过C语言的大佬应该很容易理解,先直接上代码吧
以英语字母线性表为例:

char V[30];
void build(char* v[])  
   /*字母线性表生成*/
{  int i;
   V[0]='a';
  for( i=1;   i<=n-1;   i++ ) 
  V[i]=V[i-1]+1; 
}
void display( char* v[]) 
/*字母线性表的显示*/
{  int i;
  for( i=0;  i<=n-1;  i++ )
  printf( "%c",  v[i] );
  printf( "\n " );
}

void delete(char* v[n],int k)   //删除v[n]表里的第k个(下标为k-1)。
/*字母的删除*/
{
int i;
for(i=k-1;i<n;i++)
   v[i]=v[i+1];
n--;//表长减一
}
void insert (int k,int l)
/*在k处插入数l(假设不会越界)*/
{
int i;
for(i=n;i>=k;i--)
    v[i+1]=v[i]
v[i]=l;
n++;//表长加一
}

线性表存储特点

  1. 逻辑上相邻的元素,其物理上也相邻。
  2. 若已知表中某个元素在存储器中的位置,则其他元素存放位置亦可求出(利用数组a[n]的下标)。
    设loc(a[n])表示a[n]在存储器中的首地址,L表示单个数据元素所占地址长度:则满足
    *loc(a[n+k])=loc(a[n])+k*L 和 loc(a[n])=loc(a[1])+(n-1)L

动态顺序表

这个主要是realloc(p,newsize)函数的应用,在此只引用书上内容解释下realloc的用法,不给出其他详细代码了:

realloc (p, newsize)函数的意思是:新开一片大小为newsize的连续空间,并把以p为首址的原空间数据都拷贝进去。
这是书上的一段伪代码:

Status ListInsert_Sq(SqList &L, int i, ElemType e)
{   //在顺序线性表中第i个位置之前插入新的元素e
if( i < 1 or i > L.length+1) return ERROR;  // 检验i 值的合法性
       if ( L.length ≥ L.listsize )  //若表长超过表尺寸则要增加尺寸 
  {  newbase = ( ElemType* ) realloc ( L.elem , (L.listsize + LISTINCREMENT )* sizeof ( ElemType ) );
if (newbase=NULL ) exit( OVERFLOW ) ; //分配失败则退出并报错
      L.elem = newbase ;                         //重置新基址
      L.listsize = L.listsize + LISTINCREMENT ; } //增加表尺寸

链表操作

链表存储特点

结点在存储器中的位置是随意的,即逻辑上相邻的数据元素在物理上不一定相邻。

为描述存储形式,引用一个图片:

引用的!!!!!链表的结点结构体代码:

typedef struct Lnode {
     ElemType         data;      //数据域
     struct Lnode   *next;      //指针域
}Lnode, *LnodeList;             // *LnodeList为Lnode类型的指针

链表中有头指针、头结点、首元结点的概念:

头指针:是指向链表中第一个结点(或为头结点、或为首元结点)的指针;通常头指针也是一个类似于结点的结构体
头结点:是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息,它不计入表长度。
首元结点:是指链表中存储线性表第一个数据元素a1的结点。

关于单链表的代码

  1. 创建单链表
/*创建单链表,还是存储26个字母为例*/
LnodeList build()
{
LnodeList head,p,q;
head=(LnodeList)malloc(sizeof(Lnode));
p=head;
q=head;
for( i=1; i<26; i++)         //因尾结点要特殊处理,故i≠26
{ 
p->data=i+‘a’-1;         // 第一个结点值为字符a
q=(node*)malloc(sizeof(Lnode)); //为后继结点开辟空间
p->next=q;
p=q;
}             //让指针变量p指向后一个结点
p->data=i+‘a’-1;           //最后一个元素要单独处理让其next指向空
p->next=NULL ;}
return head;
}
  1. 插入
/*在第i个元素后插入j元素*/
void insert(LnodeList head,int i,char j)
{
int k;
LnodeList p,r;
p=head;//若带头结点则为    p=head->next;
while(p&&k<i)
{
p=p->next;
k++;
}if(!p) return error;
r=(LnodeList)malloc(sizeof(Lnode));
r->data=j;
r->next=p->next;
p->next=r;
}
  1. 修改
/*把第i个元素关键字改成j*/
void change(LnodeList head,int i,char j)
{int k;
LnodeList p,r;
p=head;//若带头结点则为    p=head->next;
while(p&&k<i)
{
p=p->next;
k++;
}if(!p) return error;
 p->data =j;   //读取第i个结点的代码仅需要把这句改成:printf("%c",p->data);
}
  1. 删除
/*把第i个元素删除*/
void delete(LnodeList head,int i,char j)
{int k;
LnodeList p,q;
p=head;//若带头结点则为    p=head->next;
while(p&&k<i-1)
{
p=p->next;
k++;
}
q=p->next;
if(!p&&!q) return error;
p->next=q->next;
free(q);
  1. 逆置
void InverseList(LnodeList head){
	LnodeList p,q;
	p=head;//若带头结点则以下代码中head都改成head->next
	head=NULL;
	while(p){
		q=p;
		p=p->next;
		q->next=head;
		head=q;
	}//while
}

下图是逆置的代码一部分的图示:
在这里插入图片描述

这里引用一段循环单链表的逆置核心算法

/*循环单链表的逆置核心语句*/
//替换法
q=head;//逆置后的第一个结点
p=head->next; //有头结点
while(p!=head) //循环单链表
{  r=p->next;
    p->next=q;  //前驱变后继
   q=p;
   p=r; }  //准备处理下一结点
head->next=q; // 以an为首

//插入法
p=head->next; //有头结点
if(p!=head){r=p->next; 
  p->next =head;p=r}; //处理a1
while(p!=head) //循环单链表
{ r=p ->next    //保存原后继
   p ->next= head->next;
   head->next=p; 
  p=r;} //准备处理下一结点

  1. 两个单链表合并(并且按照从小到大的顺序)
/*原链表head1和head2都有序*/
LnodeList p,q,r,s,t;
p=head1;
q=head2;   //head1和head2都有头结点
r=p->next;
s=q->next;
while(p&&q)    //归并到head2去
{
if(r->data>s->data)
{p->next=s;
q->next=p;
q=s;
s=s->next;
p=r;
r=r->next;}
else 
{t=p;
p=r;
r=r->next;
p->next=s->next;
s->next=p;
t->next=r;
p=t;
s=s->next;
q=q->next;
}
if (p&&!q)
s->next=p;
}

以上代码是单纯的指针方向改变的运算,可能不完善、有bug,还请各位大佬指正,下面给出另一种算法

LnodeList p1,p2,head3,p3;
p1=head1->next;  
p2=head2->next;   
head3=pc=head1; //有头结点
while(p1&&p2)        //将p1 、p2结点按大小依次插入head3中
            { if(p1->data<=p2->data)
                {p3->next=p1; 
                 p3=p1;  
                 p1=p1->next;}
              else {p3->next=p2;  
                    p3=p2;  
                    p2=p2->next}  
             }
p3->next = p1 ? p1: p2 ;     //插入非空表的剩余段
            free(head2);    //释放head2的头结点

  1. 单链表的直接插入排序运算
    这个算法的思想我参考了插入排序的思想,祥见:插入排序
r=head;
q=head->next;
while(q)
{
p=head;
if(q->data<r->data)
  {t=q->next;
  while(p->data<=q->data) 
      p=p->next;
  q->next=p->next;
  p->next=q;
  q=t;
  }
else
   {
   r=q;
   q=q->next;
   }
}

双链表

结构体:

typedef struct tnode {
     ElemType     data;      //数据域
     struct tnode   *next,*last;      //指针域
}tnode, *tnodeList;             // *tnodeList为tnode类型的指针

  1. 创建双链表
/*创建单链表,还是存储26个字母为例*/
LnodeList build()
{
tnodeList head,p;
head=(tnodeList)malloc(sizeof(tnode));
p=head;
q=head;
for( i=1; i<26; i++)         //因尾结点要特殊处理,故i≠26
{ 
p->data=i+‘a’-1;         // 第一个结点值为字符a
q=(node*)malloc(sizeof(tnode)); //为后继结点开辟空间
q->last=p;
p->next=q;
p=q;
}             //让指针变量p指向后一个结点
p->data=i+‘a’-1;           //最后一个元素要单独处理让其next指向空
p->next=NULL ;}
return head;
}
  1. 插入操作:
/*在第i个元素后插入j元素*/
void insert(tnodeList head,int i,char j)
{
int k;
tnodeList p,q,r;
p=head;//若带头结点则为    p=head->next;
while(p&&k<i)
{
p=p->next;
k++;
}if(!p) return error;
q=p->next;
r=(LnodeList)malloc(sizeof(Lnode));
r->data=j;
r->next=p->next;
r->last=q->last;
p->next=r;
q->last=r;
  1. 删除操作:
/*删除第i个元素*/
void insert(tnodeList head,int i,char j)
{
int k;
tnodeList p,q,r;
p=head;//若带头结点则为    p=head->next;
while(p&&k<i-1)
{
p=p->next;
k++;
}if(!p) return error;
q=p->next;
r=q->next;
p->next=r;
r->last=p;
free(q);

以上是笔者面临期末考试心血来潮写的一些《数据结构》知识点,算是一个总结吧,之后的章节不一定会有空写了,部分代码可能会有bug还请各位大佬多多指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值