数据结构与算法C语言

二、线性表

1.线性表的定义和基本操作

定义

线性表是具有相同数据类型的 n (n>0)个数据元素的有限序列,其中 n 为表长,当n = 0时线性表是一个空表。若用L命名线性表,则其一般表示为
L=(a1,a2..·,ai, ai+1,....·,an)

,a1 是唯一的“第一个”数据元素,又称表头元素;an是唯一的“最后一个”数据元素,又称表尾元素。除第一个元素外,每个元素有且仅有一个直接前驱。除最后一个元素外,每个元素有且仅有一个直接后继.

特性:

(1)有穷性:一个线性表中的元素个数是有限的。
(2)一致性:一个线性表中所有元素的性质相同。从实现的角度看,所有元素具有相同的数据类型。
(3)序列性:一个线性表中所有元素之间的相对位置是线性的,即存在唯一的开始元素和终端元素,除此之外,每个元素只有唯一的前驱元素和后继元素。各元素在线性表中的位置只取决于它们的序号,所以在一个线性表中可以存在两个值相同的元素。

ADT List
{
        数据对象:
        D=(ai|1<=i<=n,n=>0,ai为 ElemType类型)                //ElemType是自定义类型标识符
        数据关系:
        R={<ai,ai+1>|ai,ai+1∈D,i=1,..,n-1)
        基本运算:
        InitList(&L):初始化线性表,构造一个空的线性表 L。
        DestroyList(&L):销毁线性表,释放为线性表 L分配的内存空间。
        ListEmpty(L): 判断线性表是否为空表,若 L为空表,则返回真,否则返回假
        ListLength(L): 求线性表的长度,返回L中元素的个数。
        DispList(L):输出线性表,当线性表L不为空时顺序输出L 中各元素值
        GetElem(L,i,&e): 按序号求线性表中元素用e返回 L 中第 i(1<=i<=n)个元素值
        LocateElem(L,e):按元素值查找,返回L中第一个值为e 相等的元素序号。
        ListInsert(&L,i,e): 插人元素,在 L的第i(1i n+1)个位置插人一个新元素e。            
        ListDelete(&L,i,&e): 删除元素,删除L的第i(1<=i<=n)个元素,并用e 返回该元素值
}

2.线性表的顺序表示

1)顺序表的定义:

逻辑顺序与其物理顺序相同;每个数据元素的存储位置都和线性表的起始位置相差一个和该数据元素的位序成正比的常数,顺序表中的任意一个数据元素都可以随机存取,缺点,空间大小不确定时,无法预先分配空间。

注意:线性表中元素的位序是从 1开始的,而数组中元素的下标是从0开始的。

1.静态分配

#include <stdio.h>
#define MaxSize 10 //定义最大长度
typedef struct
{
   
    ElemType data[MaxSize]; //用静态的“数组”存放数据元素
    int length;        //顺序表的当前长度
} SqList;                //顺序表的类型定义。

2.动态分配:

#include <stdio.h>
#include <stdlib.h>
#define InitSize 10 //顺序表的初始长度
typedef struct 
{
 
    ElemType *data; //用静态的“数组”存放数据元素
    int MaxSize; //定义最大长度
    int length; //顺序表的当前长度
}SqList;

动态分配并不是链式存储,它同样属于顺序存储结构,物理结构没有变化,依然是随机存取方式,只是分配的空间大小可以在运行时动态决定

4.主要特点:

顺序表最主要的特点是随机访问,即通过首地址和元素序号可在时间 O(1)内找到指定的元素。
顺序表的存储密度高,每个结点只存储数据元素。
顺序表逻辑上相邻的元素物理也相邻,所以插入和删除操作需要移动大量元素。

初始化

void InitList(SqList &L)
{
   L.data = (int *)malloc(sizeof(int)*InitSize);
    L.MaxSize = InitSize;
    L.length = 0; //顺序表初始长度为0;
}
1)插入
bool ListInsert(SqList &L, int i, ElemType e) {
    //判断i的范围是否有效
    if (i < 1 || i > L.length + 1)
    {
        return false;
     
    }
    //判断当前存储空间是否已满,不能插入
    if (L.length >= MaxSize) 
    {
       
        return false;

    }
    //将第i个元素及以后的元素后移
    for (int j = L.length; j >= i; j--)
    {
      
        L.data[j] = L.data[j - 1];
    }
    //在位置i处放入e
    L.data[i - 1] = e;
    L.length++;  //长度++
    return true;
    
}

1、最好情况: 新元素插入到表尾,不需要移动元素

i = n+1,循环0次;最好时间复杂度 = O(1)

2、最坏情况: 新元素插入到表头,需要将原有的 n 个元素全都向后移动

i = 1,循环 n 次;最坏时间复杂度 = O(n)

3、平均情况: n/2;

平均时间复杂度 = O(n)

2)删除操作
bool ListDelete(SqList &L, int i, ElemType &e) {
    //判断i的范围是否有效
    if (i < 1 || i > L.length + 1)
    {
        return false;
        /* code */
    }
    e = L.data[i - 1];
    //将第i个元素及以后的元素前移
    for (int j = i; j < L.length; j++)
    {
        /* code */
        L.data[j - 1] = L.data[j];
    }
    L.length--;  //长度--
    return true;
    
}

1、最好情况: 删除表尾元素,不需要移动其他元素

i = n,循环 0 次;最好时间复杂度 = O(1)

2、最坏情况: 删除表头元素,需要将后续的 n-1 个元素全都向前移动

i = 1,循环 n-1 次;最坏时间复杂度 = O(n)

3、平均情况:平均时间复杂度 = O(n)O(n)

查找

按位查找

GetElem(L,i): 按位查找操作。获取表 L 中第 i 个位置的元素的值。

int GetElem(SeqList L,int i){
	return L.data[i-1];
}
 按值查找

LocationElem(L,e);

int LocationElem(SeqList L,int e){
	for(int i=0;i<L.length;i++)
		if(L.data[i]==e)
			return i+1;
	return 0;
}
  1. 销毁线性表

DestroyList(&L):释放线性表L占用的内存空间。

void DestroyList(Sqlist &L){
    free(L.data);
    L.length = 0;
    L.MaxSize = 0;
    L.data = nullptr;  //令其为空指针
}

  1. 判线性表是否为空表

ListEmpty(L):若L为空表,则返回真,否则返回假。

int Empty(Sqlist L){
    return L.length==0? 1 : 0;
}
  1. 求线性表的长度

ListLength(L):返回L中元素个数n

int Length(Sqlist L){
    return L.length;
}
输出线性表

DispList(L):线性表L不为空时,顺序显示L中各结点的值域

void DispList(SqList *L)
{
	for (int i=0;i<L->length;i++)
		printf("%d ",L->data[i]);
	printf("\n");
}

3.线性表的链式表示

插入和删除不需要移动元素,而只需修改指针,失去顺序表可随机存取的优点,

单链表

利用单链表可以解决顺序表需要大量连续存储单元的缺点,但单链表附加指针域,也存在浪费存储空间的缺点。由于单链表的元素离散地分布在存储空间中,所以单链表是非随机车取的存储结构,即不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从表头开始遍历,依次查找。

通常用头指针来标识一个单链表,如单链表 L,头指针为 NULL 时表示一个空表。此外,为了操作上的方便,在单链表第一个结点之前附加一个结点,称为头结点。头结点的数据域可以不设任何信息,也可以记录表长等信息。头结点的指针域指向线性表的第一个元素结点,

头结点和头指针的区分:不管带不带头结点,头指针都始终指向链表的第一个结点,而头结点是带头结点的链表中的第一个结点,结点内通常不存储信息。
引入头结点后,可以带来两个优点:
1由于第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个位置上的操作和在表的其他位置上的操作一致,无须进行特殊处理。

2无论链表是否为空,其头指针都是指向头结点的非空指针(空表中头结点的指针域为空)因此空表和非空表的处理也就得到了统一。

结点类型

typedef struct LNode{ //定义单链表结点类型
	ElemType data; //数据域,可以是别的各种数据类型,本文统一用int类型
	struct LNode *next; //指针域
}LNode, *LinkList;
初始化InitList(&L):

构造一个空的单链表L

void InitList(LinkList &L){
    L = (LNode *)malloc(sizeof(LinkList));    //    创建头节点
    L->next = NULL;                        //初始为空链表
}
头插法创建单链表

CreateListF(&L,a[],n):用头插法由数组a创建n个元素的单链表。

void CreateListF(LinkList * &L,ElemType a[],int n){            //   逆向建立单链表
    InitList(L); //初始化
    int x;
    LNode  *s;
   
    for(int i=0;i<n;i++){ //循环建立数据节点s
        s= (LinkNode *)malloc(sizeof(LinkNode));//创建新结点,
        s->data = a[i];
        s->next = L->next;
        L->next = s;                    //将新结点插入表中,L为头指针,
       
    }
    
}
  1. 尾插法创建单链表

CreateListR(&L,a[],n):用尾插法由数组a创建n个元素的单链表

void CreateListR(LinkList * &L,ElemType a[],int n){

        LinkNode *s,*r;
        InitList(L); //初始化
         r=L;                //r始终指向尾节点,初始时指向头节点,
   
    for(int i=0;i<n;i++){ //循环建立数据节点s
        s= (LinkNode *)malloc(sizeof(LinkNode));//创建新结点,
        s->data = a[i];
        r->next = s;             //将结点s插入结点r之后。 
        r=s;                         
    }
    r->next=NULL;                    //    将尾结点的next域置为NULL
}
  1. 销毁单链表

DestroyList(&L):释放单链表L占用的内存空间。

void DestroyList(LinkNode *&L)
{
	LinkNode *pre=L,*p=pre->next;
	while (p!=NULL)
	{	free(pre);
		pre=p;
		p=pre->next;
	}
	free(pre);	//此时p为NULL,pre指向尾结点,释放它
}
  1. 判单链表是否为空表

ListEmpty(L):若L为空表,则返回真,否则返回假。

bool ListEmpty(LinkNode * L){
    return(L->next == NULL);
  
}
  1. 求单链表的长度

​​​​​​​ListLength(L):返回L中元素个数n

int ListLength(LinkNode * L){
    
    int n = 0;
LNode *p = L
    while(p->next!=NULL){
        n++;
        p = p->next;
    }
    return n;
输出单链表

DispList(L):单链表L不为空时,顺序显示L中各结点的值域

void DispList(LinkNode *L)
{
	LinkNode *p=L->next;
	while (p!=NULL)
	{	printf("%d ",p->data);
		p=p->next;
	}
	printf("\n");
}
按值查找
  1. 求单链表L中指定位置的某个数据元素GetElem(Li&e):用e返回L中第 i1in)个元素的值。
bool GetElem(LinkNode * L,int i, ElemType &e){
int j=0;

LinkNode * p=L;        //p 指向头结点,j置为 0(即头结点的序号为 0)//i错误返回假//查找第 i个结点 p
if (i<=0) return false;
while (j<i&&p!-NULL){

j++;
p=p-> next;
}
if (p==NULL)        //不存在第 i个数据结点,返回 false

return false;
else{                //存在第i个数据结点,返回 true


e=p-> data;
return true;
}
}
按位查找
  1. 定位查找LocateElem(Le):返回L中第一个值域与e相等的逻辑位序。若这样的元素不存在,则返回值为0
int LocateElem(LinkNode * L,ElemType e){

int i=1;
LinkNode * p=L-> next;        //p 指向首结点,i置为 1(即首结点的序号为 1)
while(p!=NULL&&p->data!=e)    //查找 data 值为 e的结点,其序号为 i
{p=p-> next;
i++;
}

if (p==NULL)        //不存在值为 e的结点,返回 0
return(0) ;
else                //存在值为 e的结点,返回其逻辑序号 i
return(i) ;
}


  1. 插入一个数据元素

ListInsert(&Lie):在L的第i1in)个元素之前插入新的元素eL的长度增1

bool ListInsert(LinkNode * &L,int i,ElemType e){
int j=0;

LinkNode *p=L,* s;                    //p 指向头结点,j置为 0(即头结点的序号为 0)
if (i<= 0) return false;                //i错误返回 false

while (j<i-1&&p!=NULL){                //查找第 i-1 个结点 P
j++;
p=p-> next;
}
if (p==NULL)                    //未找到第 i-1个结点 p,返回 false

return false;
else                                //找到第 i-1 个结点 p,插入新结点并返回 true
{

s=(LinkNode *)malloc(sizeof(LinkNode));    //创建新结点 s,将其 data 域置为 e

s-> data=e;

s -> next=p-> next;                    //将结点 s 插入结点 p之后
p -> next=s;
return true;
}
}
  1. 删除数据元素

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

bool ListDelete(LinkNode * &L,int i,ElemType &e){

int j-0;
LinkNode *p=L,* q;        //p指向头结点置为 0(即头结点的序号为 0)
if (i<=0) return false;        //i错误返回 false
while (j<i-1&& p!=NULL)        //查找第 i-1个结点 p
{j++;
p=p-> next;
}
if (p==NULL)        //未找到第 i-1个结点 p,返回 false
return false;
else                //找到第 i-1个结点 p
{
q=p-> next;        //q 指向第 i个结点
if (q==NULL)        //若不存在第 i个结点,返回 false
return false;


e=q-> data;
p -> next=q-> next;        //从单链表中删除 q结点
free(q);                    //释放 q 结点
return true;                //返回 true 表示成功删除第i个结点
}
}

双链表

结构定义

#include <stdio.h>
#include <malloc.h>
typedef int ElemType;
typedef struct DNode		//定义双链表结点类型
{
	ElemType data;
	struct DNode *prior;	//指向前驱结点
	struct DNode *next;		//指向后继结点
} DLinkNode;
初始化双链表

InitList(&L):构造一个空的双链表L

void InitList(DLinkNode *&L)
{
	L=(DLinkNode *)malloc(sizeof(DLinkNode));  	//创建头结点
	L->prior=L->next=NULL;
}
头插法创建双链表

CreateListF(&L,a[],n):用头插法由数组a创建n个元素的双链表

void CreateListF(DLinkNode *&L,ElemType a[],int n)
//头插法建双链表
{
	DLinkNode *s;
	L=(DLinkNode *)malloc(sizeof(DLinkNode));  	//创建头结点
	L->prior=L->next=NULL;
	for (int i=0;i<n;i++)
	{	
		s=(DLinkNode *)malloc(sizeof(DLinkNode));//创建新结点
		s->data=a[i];
		s->next=L->next;			//将结点s插在原开始结点之前,头结点之后
		if (L->next!=NULL) L->next->prior=s;
		L->next=s;s->prior=L;
	}
}
  1. 尾插法创建双链表

CreateListR(&L,a[],n):用尾插法由数组a创建n个元素的双链表。

void CreateListR(DLinkNode *&L,ElemType a[],int n)
//尾插法建双链表
{
	DLinkNode *s,*r;
	L=(DLinkNode *)malloc(sizeof(DLinkNode));  	//创建头结点
	L->prior=L->next=NULL;
	r=L;					//r始终指向终端结点,开始时指向头结点
	for (int i=0;i<n;i++)
	{	
		s=(DLinkNode *)malloc(sizeof(DLinkNode));//创建新结点
		s->data=a[i];
		r->next=s;s->prior=r;	//将结点s插入结点r之后
		r=s;
	}
	r->next=NULL;				//尾结点next域置为NULL
}
  1. 销毁双链表

​​​​​​​DestroyList(&L):释放双链表L占用的内存空间。

void DestroyList(DLinkNode *&L)
{
	DLinkNode *pre=L,*p=pre->next;
	while (p!=NULL)
	{
		free(pre);
		pre=p;
		p=pre->next;
	}
	free(pre);
}
  1. 判双链表是否为空表

ListEmpty(L):若L为空表,则返回真,否则返回假。

bool ListEmpty(DLinkNode *L)
{
	return(L->next==NULL);
}
  1. 求双链表的长度

​​​​​​​ListLength(L):返回L中元素个数n

int ListLength(DLinkNode *L)
{
	DLinkNode *p=L;
	int i=0;
	while (p->next!=NULL)
	{
		i++;
		p=p->next;
	}
	return(i);
}
  1. 输出双链表

​​​​​​​DispList(L):双链表L不为空时,顺序显示L中各结点的值域。

void DispList(DLinkNode *L)
{
	DLinkNode *p=L->next;
	while (p!=NULL)
	{
		printf("%d ",p->data);
		p=p->next;
	}
	printf("\n");
}
按值查找
  1. 求双链表L中指定位置的某个数据元素GetElem(Li&e):用e返回L中第 i1in)个元素的值。
bool GetElem(DLinkNode *L,int i,ElemType &e)
{
	int j=0;
	DLinkNode *p=L;
	if (i<=0) return false;		//i错误返回假
	while (j<i && p!=NULL)
	{
		j++;
		p=p->next;
	}
	if (p==NULL)
		return false;
	else
	{
		e=p->data;
		return true;
	}
}
按位查找
  1. 定位查找LocateElem(Le):返回L中第一个值域与e相等的逻辑位序。若这样的元素不存在,则返回值为0
int LocateElem(DLinkNode *L,ElemType e)
{
	int n=1;
	DLinkNode *p=L->next;
	while (p!=NULL && p->data!=e)
	{
		n++;
		p=p->next;
	}
	if (p==NULL)
		return(0);
	else
		return(n);
}
  1. 插入一个数据元素

​​​​​​​ListInsert(&Lie):在L的第i1in)个元素之前插入新的元素eL的长度增1

bool ListInsert(DLinkNode *&L,int i,ElemType e)
{
	int j=0;
	DLinkNode *p=L,*s;
	if (i<=0) return false;		//i错误返回假
	while (j<i-1 && p!=NULL)
	{
		j++;
		p=p->next;
	}
	if (p==NULL)				//未找到第i-1个结点
		return false;
	else						//找到第i-1个结点p
	{
		s=(DLinkNode *)malloc(sizeof(DLinkNode));	//创建新结点s
		s->data=e;	
		s->next=p->next;		//将结点s插入到结点p之后
		if (p->next!=NULL) 
			p->next->prior=s;
		s->prior=p;
		p->next=s;
		return true;
	}
}
  1. 删除数据元素

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

bool ListDelete(DLinkNode *&L,int i,ElemType &e)
{
	int j=0;
	DLinkNode *p=L,*q;
	if (i<=0) return false;		//i错误返回假
	while (j<i-1 && p!=NULL)
	{
		j++;
		p=p->next;
	}
	if (p==NULL)				//未找到第i-1个结点
		return false;
	else						//找到第i-1个结点p
	{
		q=p->next;				//q指向要删除的结点
		if (q==NULL) 
			return false;		//不存在第i个结点
		e=q->data;
		p->next=q->next;		//从单链表中删除*q结点
		if (p->next!=NULL) p->next->prior=p;
		free(q);				//释放q结点
		return true;
	}
}

循环链表

循环单链表基本运算算法

//循环单链表基本运算算法
#include <stdio.h>
#include <malloc.h>
typedef int ElemType;
typedef struct LNode		//定义单链表结点类型
{
	ElemType data;
    struct LNode *next;
} LinkNode;
void CreateListF(LinkNode *&L,ElemType a[],int n)
//头插法建立循环单链表
{
	LinkNode *s;int i;
	L=(LinkNode *)malloc(sizeof(LinkNode));  	//创建头结点
	L->next=NULL;
	for (i=0;i<n;i++)
	{	
		s=(LinkNode *)malloc(sizeof(LinkNode));//创建新结点
		s->data=a[i];
		s->next=L->next;			//将结点s插在原开始结点之前,头结点之后
		L->next=s;
	}
	s=L->next;	
	while (s->next!=NULL)			//查找尾结点,由s指向它
		s=s->next;
	s->next=L;						//尾结点next域指向头结点

}
void CreateListR(LinkNode *&L,ElemType a[],int n)
//尾插法建立循环单链表
{
	LinkNode *s,*r;int i;
	L=(LinkNode *)malloc(sizeof(LinkNode));  	//创建头结点
	L->next=NULL;
	r=L;					//r始终指向终端结点,开始时指向头结点
	for (i=0;i<n;i++)
	{	
		s=(LinkNode *)malloc(sizeof(LinkNode));//创建新结点
		s->data=a[i];
		r->next=s;			//将结点s插入结点r之后
		r=s;
	}
	r->next=L;				//尾结点next域指向头结点
}
void InitList(LinkNode *&L)
{
	L=(LinkNode *)malloc(sizeof(LinkNode));	//创建头结点
	L->next=L;
}
void DestroyList(LinkNode *&L)
{
	LinkNode *p=L,*q=p->next;
	while (q!=L)
	{
		free(p);
		p=q;
		q=p->next;
	}
	free(p);
}
bool ListEmpty(LinkNode *L)
{
	return(L->next==L);
}
int ListLength(LinkNode *L)
{
	LinkNode *p=L;int i=0;
	while (p->next!=L)
	{
		i++;
		p=p->next;
	}
	return(i);
}
void DispList(LinkNode *L)
{
	LinkNode *p=L->next;
	while (p!=L)
	{
		printf("%d ",p->data);
		p=p->next;
	}
	printf("\n");
}
bool GetElem(LinkNode *L,int i,ElemType &e)
{
	int j=0;
	LinkNode *p;
	if (L->next!=L)		//单链表不为空表时
	{
		if (i==1)
		{
			e=L->next->data;
			return true;
		}
		else			//i不为1时
		{
			p=L->next;
			while (j<i-1 && p!=L)
			{
				j++;
				p=p->next;
			}
			if (p==L)
				return false;
			else
			{
				e=p->data;
				return true;
			}
		}
	}
	else				//单链表为空表时
		return false;
}
int LocateElem(LinkNode *L,ElemType e)
{
	LinkNode *p=L->next;
	int n=1;
	while (p!=L && p->data!=e)
	{
		p=p->next;
		n++;
	}
	if (p==L)
		return(0);
	else
		return(n);
}
bool ListInsert(LinkNode *&L,int i,ElemType e)
{
	int j=0;
	LinkNode *p=L,*s;
	if (p->next==L || i==1)		//原单链表为空表或i==1时
	{
		s=(LinkNode *)malloc(sizeof(LinkNode));	//创建新结点s
		s->data=e;								
		s->next=p->next;		//将结点s插入到结点p之后
		p->next=s;
		return true;
	}
	else
	{
		p=L->next;
		while (j<i-2 && p!=L)
		{
			j++;
			p=p->next;
		}
		if (p==L)				//未找到第i-1个结点
			return false;
		else					//找到第i-1个结点p
		{
			s=(LinkNode *)malloc(sizeof(LinkNode));	//创建新结点s
			s->data=e;								
			s->next=p->next;						//将结点s插入到结点p之后
			p->next=s;
			return true;
		}
	}
}
bool ListDelete(LinkNode *&L,int i,ElemType &e)
{
	int j=0;
	LinkNode *p=L,*q;
	if (p->next!=L)					//原单链表不为空表时
	{
		if (i==1)					//i==1时
		{
			q=L->next;				//删除第1个结点
			e=q->data;
			L->next=q->next;
			free(q);
			return true;
		}
		else						//i不为1时
		{
			p=L->next;
			while (j<i-2 && p!=L)
			{
				j++;
				p=p->next;
			}
			if (p==L)				//未找到第i-1个结点
				return false;
			else					//找到第i-1个结点p
			{
				q=p->next;			//q指向要删除的结点
				e=q->data;
				p->next=q->next;	//从单链表中删除q结点
				free(q);			//释放q结点
				return true;
			}
		}
	}
	else return false;
}

循环双链表基本运算算法

//循环双链表基本运算算法
#include <stdio.h>
#include <malloc.h>
typedef int ElemType;
typedef struct DNode		//定义双链表结点类型
{
	ElemType data;
	struct DNode *prior;	//指向前驱结点
	struct DNode *next;		//指向后继结点
} DLinkNode;
void CreateListF(DLinkNode *&L,ElemType a[],int n)
//头插法建立循环双链表
{
	DLinkNode *s;int i;
	L=(DLinkNode *)malloc(sizeof(DLinkNode));  	//创建头结点
	L->next=NULL;
	for (i=0;i<n;i++)
	{	
		s=(DLinkNode *)malloc(sizeof(DLinkNode));//创建新结点
		s->data=a[i];
		s->next=L->next;			//将结点s插在原开始结点之前,头结点之后
		if (L->next!=NULL) L->next->prior=s;
		L->next=s;s->prior=L;
	}
	s=L->next;	
	while (s->next!=NULL)			//查找尾结点,由s指向它
		s=s->next;
	s->next=L;						//尾结点next域指向头结点
	L->prior=s;						//头结点的prior域指向尾结点

}
void CreateListR(DLinkNode *&L,ElemType a[],int n)
//尾插法建立循环双链表
{
	DLinkNode *s,*r;int i;
	L=(DLinkNode *)malloc(sizeof(DLinkNode));  //创建头结点
	L->next=NULL;
	r=L;					//r始终指向尾结点,开始时指向头结点
	for (i=0;i<n;i++)
	{	
		s=(DLinkNode *)malloc(sizeof(DLinkNode));//创建新结点
		s->data=a[i];
		r->next=s;s->prior=r;	//将结点s插入结点r之后
		r=s;
	}
	r->next=L;				//尾结点next域指向头结点
	L->prior=r;				//头结点的prior域指向尾结点
}
void InitList(DLinkNode *&L)
{
	L=(DLinkNode *)malloc(sizeof(DLinkNode));  	//创建头结点
	L->prior=L->next=L;
}
void DestroyList(DLinkNode *&L)
{
	DLinkNode *p=L,*q=p->next;
	while (q!=L)
	{
		free(p);
		p=q;
		q=p->next;
	}
	free(p);
}
bool ListEmpty(DLinkNode *L)
{
	return(L->next==L);
}
int ListLength(DLinkNode *L)
{
	DLinkNode *p=L;
	int i=0;
	while (p->next!=L)
	{
		i++;
		p=p->next;
	}
	return(i);
}
void DispList(DLinkNode *L)
{
	DLinkNode *p=L->next;
	while (p!=L)
	{
		printf("%d ",p->data);
		p=p->next;
	}
	printf("\n");
}
bool GetElem(DLinkNode *L,int i,ElemType &e)
{
	int j=0;
	DLinkNode *p;
	if (L->next!=L)		//双链表不为空表时
	{
		if (i==1)
		{
			e=L->next->data;
			return true;
		}
		else			//i不为1时
		{
			p=L->next;
			while (j<i-1 && p!=L)
			{
				j++;
				p=p->next;
			}
			if (p==L)
				return false;
			else
			{
				e=p->data;
				return true;
			}
		}
	}
	else				//双链表为空表时
		return 0;
}
int LocateElem(DLinkNode *L,ElemType e)
{
	int n=1;
	DLinkNode *p=L->next;
	while (p!=NULL && p->data!=e)
	{
		n++;
		p=p->next;
	}
	if (p==NULL)
		return(0);
	else
		return(n);
}
bool ListInsert(DLinkNode *&L,int i,ElemType e)
{
	int j=0;
	DLinkNode *p=L,*s;
	if (p->next==L)					//原双链表为空表时
	{	
		s=(DLinkNode *)malloc(sizeof(DLinkNode));	//创建新结点s
		s->data=e;
		p->next=s;s->next=p;
		p->prior=s;s->prior=p;
		return true;
	}
	else if (i==1)					//原双链表不为空表但i=1时
	{
		s=(DLinkNode *)malloc(sizeof(DLinkNode));	//创建新结点s
		s->data=e;
		s->next=p->next;p->next=s;	//将结点s插入到结点p之后
		s->next->prior=s;s->prior=p;
		return true;
	}
	else
	{	
		p=L->next;
		while (j<i-2 && p!=L)
		{	j++;
			p=p->next;
		}
		if (p==L)				//未找到第i-1个结点
			return false;
		else					//找到第i-1个结点*p
		{
			s=(DLinkNode *)malloc(sizeof(DLinkNode));	//创建新结点s
			s->data=e;	
			s->next=p->next;	//将结点s插入到结点p之后
			if (p->next!=NULL) p->next->prior=s;
			s->prior=p;
			p->next=s;
			return true;
		}
	}
}
bool ListDelete(DLinkNode *&L,int i,ElemType &e)
{
	int j=0;
	DLinkNode *p=L,*q;
	if (p->next!=L)					//原双链表不为空表时
	{	
		if (i==1)					//i==1时
		{	
			q=L->next;				//删除第1个结点
			e=q->data;
			L->next=q->next;
			q->next->prior=L;
			free(q);
			return true;
		}
		else						//i不为1时
		{	
			p=L->next;
			while (j<i-2 && p!=NULL)		
			{
				j++;
				p=p->next;
			}
			if (p==NULL)				//未找到第i-1个结点
				return false;
			else						//找到第i-1个结点p
			{
				q=p->next;				//q指向要删除的结点
				if (q==NULL) return 0;	//不存在第i个结点
				e=q->data;
				p->next=q->next;		//从单链表中删除q结点
				if (p->next!=NULL) p->next->prior=p;
				free(q);				//释放q结点
				return true;
			}
		}
	}
	else return false;					//原双链表为空表时
}

表连接算法

//线性表的应用:两个表的简单自然连接的算法
#include <stdio.h>
#include <malloc.h>
#define MaxCol  10			//最大列数
typedef int ElemType;
typedef struct Node1		//数据结点类型
{	
	ElemType data[MaxCol];
	struct Node1 *next;		//指向后继数据结点
} DList;
typedef struct Node2		//头结点类型
{	
	int Row,Col;			//行数和列数
	DList *next;			//指向第一个数据结点
} HList;
void CreateTable(HList *&h)
{
	int i,j;
	DList *r,*s;
	h=(HList *)malloc(sizeof(HList));		//创建头结点
	h->next=NULL;
	printf("表的行数,列数:");
	scanf("%d%d",&h->Row,&h->Col);
	for (i=0;i<h->Row;i++)
	{	printf("  第%d行:",i+1);
		s=(DList *)malloc(sizeof(DList));	//创建数据结点
		for (j=0;j<h->Col;j++)				//输入一行的数据初步统计
			scanf("%d",&s->data[j]);
		if (h->next==NULL)					//插入第一个数据结点
			h->next=s;
		else								//插入其他数据结点
			r->next=s;						//将结点s插入到结点r结点之后
		r=s;								//r始终指向最后一个数据结点
	}
	r->next=NULL;							//表尾结点next域置空
}
void DispTable(HList *h)
{
	int j;
	DList *p=h->next;
	while (p!=NULL)
	{	for (j=0;j<h->Col;j++)
			printf("%4d",p->data[j]);
		printf("\n");
		p=p->next;
	}
}
void LinkTable(HList *h1,HList *h2,HList *&h)
{
	int f1,f2,i;
	DList *p=h1->next,*q,*s,*r;
	printf("连接字段是:第1个表位序,第2个表位序:");
	scanf("%d%d",&f1,&f2);
	h=(HList *)malloc(sizeof(HList));
	h->Row=0;
	h->Col=h1->Col+h2->Col;
	h->next=NULL;
	while (p!=NULL)
	{	q=h2->next;
		while (q!=NULL)
		{	if (p->data[f1-1]==q->data[f2-1])		//对应字段值相等
			{	s=(DList *)malloc(sizeof(DList));	//创建一个数据结点
				for (i=0;i<h1->Col;i++)				//复制表1的当前行
					s->data[i]=p->data[i];
				for (i=0;i<h2->Col;i++)
					s->data[h1->Col+i]=q->data[i];	//复制表2的当前行
				if (h->next==NULL)				//插入第一个数据结点
					h->next=s;
				else							//插入其他数据结点
					r->next=s;
				r=s;							//r始终指向最后数据结点
				h->Row++;						//表行数增1
			}
			q=q->next;							//表2下移一个记录
		}
		p=p->next;								//表1下移一个记录
	}
	r->next=NULL;								//表尾结点next域置空
}
int main()
{
	HList *h1,*h2,*h;
	printf("表1:\n");	
	CreateTable(h1);			//创建表1
	printf("表2:\n");  
	CreateTable(h2);			//创建表2
	LinkTable(h1,h2,h);			//连接两个表
	printf("连接结果表:\n");	
	DispTable(h);				//输出连接结果
	return 1;
}

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

初遇在光年之外

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值