线性表的链式存储即形成链表。在链式存储结构中,每个存储结点不仅包含所存元素本身的信息即数据域,还包含元素之间的逻辑关系,即前驱结点包含有后继结点的地址信
息,这就是指针域.从而提高数据的查找速度。
头结点的引入是为了插入和删除的方便。通过头结点指针唯一标识一个链表。
单链表:形式如下
LinkList类型的定义如下:
typedef struct LNode /*定义单链表结点类型*/
{
ElemType data; /* 数据元素 */
struct LNode *next; /* 指向后继结点 */
} LinkList, *pLinkList;--------------------结点类型
单链表基本运算的实现:
(1)建立单链表:常用两种方法头插法和尾插法。
①头插法建表:该方法从一个空表开始,读取字符数组a中的字符,生成新结点,将读取的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头上,直到结束为止。采用
头插法建表的算法如下:
void CreatListF(LinkList *&L, ElemType a[], int n)
{
LinkList *s;
int i;
L = (LinkList*)malloc(sizeof(LinkLIst));/*创建头结点*/
L->next = NULL;
for(i = 0; i< n; i++)
{
s = (LinkList*)malloc(sizeof(LinkList));/* 创建新结点 */
s->data = a[i];
s->next = L->next;/* 将*s插在原开始结点之前,头结点之后 */
L->next = s;
}
}
采用头插法建立链表的的过程如下:
②尾插法建表:头插法建表虽简单,但建立的链表顺序和原数组的顺序相反。若想生成的次序一致,可采用尾插法建表。即将新结点插到链表的表尾上,为此必须增加一个尾指
针,使其始终指向当前链表的尾结点。采用尾插法建表的算法如下:
void CreatListR(LinkList *&L, ElemType a[], int n)
{
LinkList *s, *r, int i;
L = (LinkList*) malloc (sizeof(LinkList));/* 创建头结点 */
r= L; /* r始终指向终端结点,开始时指向头结点 */
for(i= 0; i < n; i++)
{
s=(LinList*)malloc(sizeof(LinkList)); /* 创建新结点 */
s->data = a[i];
r->next=s;/* 将*s插入到*r之后 */
r=s;
}
r->next = NULL;/* 终端结点next域值为null */
}
尾插法建立链表的过程如下:
(2)单链表插入结点运算:将值为X的新结点插入到单链表的第i个结点的位置上。链表的插入也分为向前、向后插入两种形式。
单链表的插入算法实现如下(先在单链表中找到第i -1 个结点*p,若存在这样的结点,将值为e的结点*s插入到其后):
int ListInsert(LinkList *&L, int i, ElemType e)
{
int j = 0;
LinkList *p = L, *s;
while (j < i - 1 && p != null )/* 查找第i - 1个结点 */
{
j++;
p = p->next;
}
if(p == NULL)
{
return 0; /* 未找到 */
}
else
{
s= (LinkList*)malloc(sizeof(LinkList));
s->data = e;
s->next = p->next;
p->next = s;
return 1;
}
}
代码如下:
LinkList * insert (LinkList* head, int num)
{
LinkList *p0,*p1,*p2;
p1 = head;
p0 = (LinkList*)malloc(sizeof(LinkList));
p0->data = num;
while(p0->data > p1->data && p1->next != NULL)
{
p2=p1;
p1=p1->next;
}
if (p0->data <= p1->data)
{
if(head == p1)
{
p0->next = p1;
head = p0;
}
else
{
p2->next = p0;
p0->next = p1;
}
}
else
{
p1->next = p0;
p0->next = null;
}
return (head);
}
(3)单链表的删除结点运算:先在单链表中找到第i-1个结点*p,若存在这样的结点,且存在后继结点,则删除该后继结点。
算法如下:
int ListDelete (LinkList *&L, int i, ElemType &e)
{
int j = 0;
LinkList *p = L;
LinkList *q;
while(j < i - 1 && p != null) /* 查找第i - 1个结点 */
{
j++;
p = p->next;
}
if(p == null) /* 未找到逻辑位序为i -1 结点 */
{
return 0;
}
else /* 找到逻辑位序为i -1 结点 */
{
q = p->next; /* q指向要删除的结点 */
if(q == null)
{
return 0; /* 若不存在第i个结点则返回0 */
}
else
{
p->next = q->next;/* 从单链表中删除*q结点 */
free(q); /* 释放结点 */
return 1;
}
}
}
代码如下:
LinkList* del(LinkList * head ,int num)
{
LinkList *p1,*p2;
p1 = head;
while (num != p1->data && p1->next != null)
{
p2 = p1;
p1 = p1->next;
}
if (num == p1->data)
{
if (p1 == head)
{
head = p1->next;
free(p1);
}
else
{
p2->next = p1->next;
free(p1);
}
}
else
{
printf("can not find!");
}
return head;
}
(4)单链表排序:
算法如下:
①void sort(LinkList *&L)
{
LinkList *p = L->next;
LinkList *q;
LinkList *r;
if (p != null)/* 若原单链表中有一个或以上的数据结点 */
{
r = p->next; /* r保存*p结点后继结点的指针 */
p->next = NULL; /* 构造只含一个结点的有序表 */
p = r;
while(p != null)
{
r = p->next;
q = L;
while(q->next != null && q->next->data < p->data)
{
q= q->next; /* 在有序表中找插入*p的前驱结点*q */
p->next = q->next; /* 将*p插入*q之后 */
q->next = p;
p = r; /* 扫描原单链表余下的结点 */
}
}
}
}
②LinkList *sort (LinkList *head)
{
LinkList *p, *p2, *p3;
int n;
int temp;
n = length(head);
if(head == null ||head->next == null)
return head;
p = head;
for(int j = 1; j < n; j++)
{
p = p->head;
for(int i = 0; i < n- j; i++)
{
if(p->data > p->next->data)
{
temp = p->data;
p->data = p>next->data;
p->next->data = temp;
}
p = p->next;
}
}
return head;
}
(5)单链表逆置:
①:利用辅助指针
LinkList *reverse (LinkList *head)
{
LinkList *p1,*p2,*p3;
if(head == null || head->next == null)
{
return head;
}
p1 = head;
p2 = head->next;
while(p2)
{
p3 = p2->next;
p2->next = p1;
p1 = p2;
p2 = p3;
}
}
②:递归
void reverse (LinkList * pCur, LinkList *& ListHead)
{
if((NULL == pCur) || (null == pCur->next))
{
ListHead = pCur;
}
else
{
LinkList* pNext = pCur->next;
reverse (pNext, ListHead);
pNext->next = pCur;
pCur->next = null;
}
}
LinkList* reverse (LinkList* pCur, LinkList *& ListHead)
{
if ((null == pCur) || (null == pCur->next))
{
ListHead = pCur;
return pCur;
}
else
{
LinkList* pTemp = reverse(pCur->next,ListHead);
pTemp->next = pCur;
pCur->next = null;
return pCur;
}
}
(6)单链表在不知道长度的情况下,求中间节点:设立两个指针,一个每次移动两个位置,一个每次移动一个位置,当前者到达最后一个结点时,后者就是中间节点。
算法如下:void searchmid(node * head,node*mid)
{
node *temp = head;
while (head->next->next != NULL)
{
head = head->next->next;
temp = temp->next;
mid = temp;
}
}
(7)单链表初始化:
LinkList LinkListInit()
{
LinkList head;
head = (LNode*)malloc(sizeof(LNode));
if(null == head)
{
cout<<"申请空间失败!";
}
head->next = null;
head->data = 0;
return head;
}
/* 创建单链表,增加元素 */
bool LinkList_Creat(LinkList* head,ElemType e)
{
LinkList* temp;
temp = head;
while(temp->next != null)
{
temp = temp->next;
}
temp->next = (LNode*)malloc(sizeof(LNode));
temp->next->next = null;
head->data++;
return 0;
}