您的位置:首页 > 理论基础 > 数据结构算法

单链表的表示和实现 - 数据结构

2013-05-20 21:23 567 查看
欢迎访问我的新博客:http://www.milkcu.com/blog/

原文地址:

基本概念

链式存储结构,不要求逻辑上相邻的元素在物理上也相邻,没有顺序存储结构所具有的的弱点(在作插入或删除操作是,需移动大量元素),但同时也失去了顺序表可随机存取的优点。

单链表的结点由数据域和指针域构成,多个结点链结成一个链表。

代码实现

# include <stdio.h>
# include <stdlib.h>
# define OK 1
# define ERROR -1
# define OVERFLOW -2

typedef int ElemType;
typedef int Status;

typedef struct Lnode {
ElemType data;
struct Lnode * next;
} Lnode, * LinkList;

Status GetElem_L(LinkList L, int i, ElemType & e);
Status ListInsert_L(LinkList & L, int i, ElemType e);
Status ListDelete_L(LinkList & L, int i, ElemType & e);
void CreateList_L(LinkList & L, int n);
void MergeList_L(LinkList & La, LinkList & Lb, LinkList & Lc);
Status ShowList_L(LinkList L);

int main(void)
{
//测试函数
LinkList L;
CreateList_L(L, 8);
ShowList_L(L);    //print create
ListInsert_L(L, 3, 3);
ShowList_L(L);    //print insert
ElemType e;
ListDelete_L(L, 4, e);
printf("delete e = %d\n", e);    //print e delete
ShowList_L(L);    //print delete
GetElem_L(L, 5, e);
printf("getelem e = %d\n", e);    //print getelem
LinkList Lb;
CreateList_L(Lb, 5);
ShowList_L(Lb);    //print Lb
LinkList Lc;
MergeList_L(L, Lb, Lc);
ShowList_L(Lc);    //print Lc
return 0;
}

Status GetElem_L(LinkList L, int i, ElemType & e)
{
//算法2.8
//L为带头结点的单链表的头指针
Lnode * p = L->next;
int j = 1;
for(j = 1; p && j < i; j++) {
p = p->next;
}
if(!p) {
return ERROR;
}
e = p->data;
return OK;
}

Status ListInsert_L(LinkList & L, int i, ElemType e)
{
//算法2.9
//在带头结点的单链线性表L中第i个位置之前插入元素e
Lnode * p = L->next;
int j = 1;
Lnode * s = (Lnode * ) malloc(sizeof(Lnode));
s->data = e;
for(j =1; p && j < i - 1; j++) {
p = p->next;
}
if(!p) {
return ERROR;
}
s->next = p->next;
p->next = s;
return OK;
}

Status ListDelete_L(LinkList & L, int i, ElemType & e)
{
//算法2.10
Lnode * p = L->next;
int j = 1;
for(j = 1; p && j < i - 1; j++) {
p = p->next;
}
if(!p) {
return ERROR;
}
Lnode * q;
q = p->next;
e = q->data;
p->next = q->next;
free(q);
return OK;
}

void CreateList_L(LinkList & L, int n)
{
//算法2.11
//逆位序输入n个元素的值,建立带表头结点的单链线性表L
L = (LinkList) malloc(sizeof(Lnode));
L->next = NULL;
for(int i = 0; i < n; i++) {
Lnode * p = (Lnode * ) malloc(sizeof(Lnode));
scanf("%d", & p->data);
p->next = L->next;
L->next = p;
}
}

void MergeList_L(LinkList & La, LinkList & Lb, LinkList & Lc)
{
//算法2.12
//归并非递减排列的La和Lb到Lc
//用La的头结点作为Lc的头结点
//本算法具有副作用
Lnode * pa = La->next;
Lnode * pb = Lb->next;
Lc = La;
Lnode * pc = Lc;
while(pa && pb) {
if(pa->data <= pb->data) {
pc->next = pa;
pc = pc->next;
pa = pa->next;
} else {
pc->next = pb;
pc = pc->next;
pb = pb->next;
}
}
pc = (pa ? pa : pb);
free(Lb);
}

Status ShowList_L(LinkList L)
{
Lnode * p = L->next;
if(!p) {
return ERROR;
}
while(p) {
printf("%d  ", p->data);
p = p->next;
}
putchar('\n');
return OK;
}

算法分析

GetElem_L()、ListInsert_L()、ListDelete_L()的时间复杂度均为O(n)。

对于算法2.9的ListInsert_L()也可通过下面改进算法实现,该算法对于在单链表中指定结点前插入结点比较实用(时间复杂度为O(1)),代码如下:

Status ListInsert_L(LinkList & L, int i, ElemType e)
{
//算法2.9改进版
//在带头结点的单链线性表L中第i个位置之前插入元素e
Lnode * p = L->next;
int j = 1;
Lnode * s = (Lnode * ) malloc(sizeof(Lnode));
for(j = 1; p && j < i; j++) {
p = p->next;
}
if(!p) {
return ERROR;
}
//最终目的是在p前插入s
s->next = p->next;
p->next = s;
s->data = p->data;
p->data = e;
}

对于算法2.10的ListDelete_L()也可通过下面函数实现,该算法对在于单链表中删除指定结点比较实用(时间复杂度为O(1)),代码如下:

Status ListDelete_L(LinkList & L, int i, ElemType & e)
{
//算法2.10改进版
//在带头结点的单链线性表L中,删除第i个元素,并由e返回其值
//未引入临时变量
Lnode * p = L->next;
int j = 1;
for(j = 1; p && j < i; j++) {
p = p->next;
}
if(!p) {
return ERROR;
}
e = p->data;
p->data = p->next->data;
p->next = p->next->next;
free(& p->next);
return OK;
}

其实上面两个改进算法,在填空选择中经常用到。

参考资料

《数据结构:C语言版》(严蔚敏,吴伟民编著)

(全文完)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: