线性表数据结构类型定义及相关操作总结

1、顺序存储结构(如数组)

定义:

#define MAXSIZE 20
typedef struct{
	int data[MAXSIZE]; //假设这里是整型
	int length;  //线性表长度
};

读取其中某个元素:假设线性顺序表已存在,读取其中第i个元素,其值返回到e中

#define ERROR 0
#define OK 1   //定义返回状态
int GetElem(Squlist L, int i, int *e){
	if (L.length == 0 || i<1 || i>L.length)  //该元素不存在或者超出表范围或者表为空则读取失败
		return ERROR;
	*e = L.data[i - 1];
	return OK;  //读取成功
};
插入操作:在第i个元素前面插入元素e

int ListInsert(Squlist *L, int i, int e){
	int k;
	if (L->length == MAXSIZE) //表格是否满
		return ERROR;
	if (i<1 ||i>length+1)  //插入i不在范围内
		return ERROR;
	if (i <= L->length)
	{
		for (k = length - 1; k >= i - 1; k--) 
			L->data[k + 1] = L->data[k];
	}
	   L->data[i] = e;
           length++;
	   return OK;
	
};
删除操作:删除第i个元素并返回其值e

int ListDelete(Squlist *L, int i, int *e){
	int k;
	if (L->length == 0)      //表格为空
		return ERROR;
	if (i<1 || i>L->length)  //删除位置不正确
		return ERROR;
	if (i <= L->length){
		*e = L->data[i - 1];
		for (k = i; k < L->length - 1;k++)
			L->data[i - 1] = L->data[i];
		L->length--;
		return OK;
	}

}

总结特点:查询元素方便(时间复杂度O(1)),插入和删除元素复杂(时间复杂度O(n))


2、链式存储结构(链表)
单链表的定义:

typedef struct Node {         //定义链表中的节点
	int data; //假设数据为整型
	struct Node *next;
};
typedef struct Node  *Linklist;  //定义一个链表类型的指针
链表读取:读取第i个数,其值返回e中

#define ERROR 0;
#define OK  1;
int GetElem(Linklist L, int i, int *e){
	int j=1;
	Linklist p;
	p = L->next;   //表示p指向了L->next,理解这点很重要
	while (p && j < 1){
		p = p->next;
		j++;
	}
	if (!p || j > i)
		return ERROR; 
	&e = p->data;
	return OK;
}

链表整表创建:头插法

void CreatLinklist(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;
		(->next = p;       //插入到表头
	}	
}
链表的插入:在第i个元素前面插入元素e

int LinklistInsert(LinkList L, int i, int e){
	int j;
	Linklist s, p;
	p = L;
	while (p && j < i){     //先找到插入的位置
		p = p->next;
		j++;
	}
	if (!p || j > i)
		return ERROR;
	s = (Linklist)malloc(sizeof(Node));
	s->data = e;
	s->next = p->next;     //插入链表s到p的后继
	p->next = s;
	return OK;
}

链表的删除:删除第i个元素,返回其值到e中

int LinklistDelete(Linklist L, inti, int *e){
	int j = 1;
	Linklist p, q;
	p = L;
	while (p && j < i){
		p = p->next;
		j++;
	}
	if (!(p->next) || j > i)
		return ERROR;
	q = p->next;
	p->next = q->next;     //将q的后继赋值给p
	*e = q->data;
	free(q);              //系统回收此节点,释放内存
	return OK;
}
整个链表的删除:

int CleatLinklist(Linklist L){
	Linklist p, q;
	p = L->next;
	while (p){
		q = p->next;
		free(q);
		p=q
	}
	L->next = NULL;    //头结点指针域为空
	return OK;
}


总结链表的特点,可以看到每次读取一个数的时候,都要从表头一直读下去,复杂度为O(n),但是插入和删除时,找到特定位置后,再执行的时间复杂度为O(1)

3、循环链表

把单链表的终端节点指针域指向头结点,就形成了循环链表,可方便进行链表全部结点的遍历。判断的方法就是看p->next是否为头结点来结束循环


4、双向链表

和单向链表区别仅在于多了一个prior指针指向前面的结点,因此插入和删除操作也就多了几个关于prior的步骤

定义

typedef struct Node {         //定义链表中的节点
	int data; //假设数据为整型
	struct Node *next;
	struct Node *prior;
};

单链表翻转

思路是每次翻转链表,把原始链表的第一个元素后面的那个元素放到表头

LinkList ReverseLinkedList(LinkList L)
{
    Node   *first = NULL;  //指向原始链表最开始的第一个数据
    Node   *behind = NULL; //每次新生成链表时,指向原始链表最开始的第一个数据的下一个数据
 
    if (L == NULL)
    {
        return NULL;
    }
    first = L->next;
    while (first->next != NULL)
    {
        behind = first->next;
        first->next = behind->next;
        behind->next = L->next;
        L->next = behind;
    }
    return L;
}








你可能感兴趣的:(线性表数据结构类型定义及相关操作总结)