线性表之链表实现:单向链表、循环链表、双向链表

线性表

单向链表实现:

  • 优点:便于插入和删除
  • 缺点:查找数据需要遍历

声明

  • 一个数据+一个指针
typedef struct LNode *List;
struct LNode
{
	int Data;
	List next;
};

求表长

  • 遍历表,当指向节点的指针为NULL时停止
int Length(List PtrL)
{
	List p = PtrL;
	int j = 0;
	while (p)
	{
		p = p->next;
		j++;
	}
	return j;
}

查找数据

  • 当指针不为NULL或者未找到数据时,继续循环

按值查找

List Find(int X, List PtrL)
{
	List p = PtrL;
	while (p!=NULL && p->Data != X)p = p->next;
	return p;
}

按序号查找

List FindKth(int K, List PtrL)
{
	List p = PtrL;
	int i = 1;
	while (p != NULL&&i < K)
	{
		p = p->next;
		i++;
	}
	if (i == K)return p;
	else return NULL;
}

插入数据

  • 当插在第一个位置时:创建节点,让该节点直接指向头结点。
  • 当插在第i个位置时:创建节点,让该节点指向该位置的后一个节点,再让这个位置的节点指向插入的节点。
List Insert(int X, int i, List PtrL)
{
	List p, s;
	if (i == 1)
	{
		s = (List)malloc(sizeof(struct LNode));
		s->Data = X;
		s->next = PtrL;
		return s;
	}
	p = FindKth(i-1, PtrL);
	if (p == NULL)
	{
		printf("Error!");
		return NULL;
	}
	else
	{
		s = (List)malloc(sizeof(struct LNode));
		s->Data = X;
		s->next = p->next;
		p->Data = s;
		return PtrL;
	}
}

删除数据

  • 当删除头结点时,用一个临时指针指向头结点,将第二个结点当作头结点,再释放原头结点的内存。
  • 当删除中间结点时,用一个临时指针指向该中间结点,该位置结点指向下一个结点,再释放要删除的结点的内存。
  • p指针指向要删除结点的前一个结点,要注意指向的结点是否为NULL;
List Delete(int i,List PtrL)
{
	List p, s;
	if (i == 1)
	{
		s = PtrL;
		if (PtrL != NULL)PtrL = PtrL->next;
		else return NULL;
		free(s);
		return PtrL;
	}
	p = FindKth(i - 1, PtrL);
	if (p == NULL)
	{
		printf("The %d node is not exited!",i-1);
		return NULL;
		}
	else if (p->next == NULL)
	{
		printf("The %d node is not exited!", i);
		return NULL;
	}
	else
	{
		s = p->next;
		p->next = s->next;
		free(s);
		return PtrL;
	}
}

输出数据

void Print(List PtrL)
{
	while (PtrL != NULL)
	{
		printf("%d ", PtrL->Data);
		PtrL = PtrL->next;
	}
	return;
}

注意

  • 自定义的线性表并不一定更要按标准,顾名思义,自定义线性表就是自定义,完全可以自己大胆改变线性表的内容。

循环链表

  • 最后一个元素不指向空指针而是指向头节点,形成一个环,这样首尾相接的链表就称为循环链表。

优点

  • 查找第一个元素和最后一个元素花费时间降为O(1)。

改变

  • 最后一个元素指向头结点。与next原先指向空指针的操作均要改为头结点。

双向循环链表

  • 在结点中同时储存两个指针,分别用于指向前驱和后继,同时最后一个指针指向头结点。

优点

  • 便于查找前驱后继。
  • 查找第一个元素和最后一个元素花费时间降为O(1)。
  • 便于反向遍历。

实现代码

#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct node Node;
typedef struct node *link;

struct node
{
	int element;
	link left;
	link right;
};

typedef struct dlist *List;
typedef struct dlist Dlist;

typedef struct dlist
{
	int n;
	link leftEnd, rightEnd;
	link header;
};
link NewNode()
{
	link L;
	L = (link)malloc(sizeof(Node));
	return L;
}
List ListInit()
{
	node* y;
	List L = (List)malloc(sizeof(dlist));
	y = NewNode();
	y->left = y;
	y->right = y;
	L->header = y;
	L->n = 0;
	return L;
}
int ListRetrieve(int k, List L)
{
	int i = 1;
	link p;
	p = L->header->right;
	if (k<1 || k>L->n)printf("out of bounds");
	while (i < k) { p = p->right; i++; }
	return p->element;
}
int ListLocate(int x, List L)
{
	int i = 0;
	link p;
	p = L->header->right;
	L->header->element = x;
	while (p->element!=x) { p = p->right; i++; }
	return ((p == L->header) ? 0 : i);
}
void ListInsert(int x, int k, List L)
{
	int i = 0;
	link p, y;
	p = L->header;
	for (i = 1; i < k; i++) { p = p->right; }
	y = NewNode();
	y->element = x;
	y->left = p;
	y->right = p->right;
	p->right->left = y;
	p->right = y;
	L->n++;
	return;
}
int ListDelete(int k, List L)
{
	int x;
	link p;
	if (k<1 || k>L->n)printf("out of bounds");
	p = L->header;
	int i = 1;
	for (i = 1; i < k; i++)p = p->right;
	p->left->right = p->right;
	p->right = p->left;
	x = p->element;
	free(p);
	return x;
}
void PrintList(List L)
{
	link p;
	for (p = L->header->right; p != L->header; p = p->right)
		printf("%d ",p->element);
	return;
}
原文地址:https://www.cnblogs.com/vancasola/p/7622821.html