线性表相关操作思想

来源:互联网 发布:婆媳矛盾 知乎 编辑:程序博客网 时间:2024/06/07 10:02

   线性表,顾名思义,线性排列形成一个表状的结构.有两种存储结构,一为顺序存储模式,二为链表模式,各有所长,互相补足.

一、顺序存储结构

(1)特征及定义:用一段地址连续的存储单元依次存储线性表的数据元素,结构规整,多用数组来表示.

#define MAXSIZE 20    //存储空间初始分配量
typedef int ElemType;typedef struct{
<span style="white-space:pre"></span>ElemType data[MAXSIZE];//数据存储数据元素,最大值为MAXSIZE,这是在申请一块大小为20的地址连续的存储单元<span style="white-space:pre"></span>int length;//线性表当前的长度<=MAXSIZE}SqList;
(2)表的操作:

 a.获取表中第i个位置元素算法思路:第i个元素即为表中数组下标为i-1的元素;其次,i的值必须在数组下标范围内。

 b.顺序存储结构形式的线性表插入算法思路:如果插入位置不合理,抛出异常;如果线性表的长度>=数组长度,则抛出异常或者动态的增加容量;从最后一个元素开始向前遍历,到第i个位置,分别将它们都向后移动一个位置;将要插入元素填入位置i处;表长+1。

<span style="font-size:12px;">
int ListInsert(Sqlist *L,int i,ElemType e){<span style="white-space:pre"></span>int k;<span style="white-space:pre"></span>if(L->length==MAXSIZE)//顺序线性表已满return 0;if(i<1||i>L->length+1)//i不在范围内return 0;if(i<=L->length)//若插入的数据位置不在表尾时{for(k=L->length-1;k>=i-1;k--)//将插入位置之后的数据元素向后移动一位L->data[k+1]=L->data[k];}L->data[i-1]=e;//插入新元素L->length++;return 1;}</span>

 c.删除算法的思路:如果删除位置不合理,抛出异常;取出删除元素;从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置;表长-1。

<span style="font-family:SimSun;font-size:10px;">
int ListDelete(SqList *L,int i,ElemType *e){int k;if(L->length==0)return 0;if(i<1||i>L->length)return 0;*e=L->data[i-1];if(i<L->length){for(k=i;k<L->length;k++)L->data[k-1]=L->data[k];}L->length--;return 1;}</span>

(3)优点:快速存取表中任意位置的元素,插入和删除操作需要移动大量元素,存储空间易产生碎片。

二、链表存储结构

(1)特征及定义:存储单元不一定连续,结构多用指针。

typedef struct Node{ElemType data;struct Node *next;}Node;typedef struct Node *LinkList;
   假如说p是指向第i个元素的指针,那么这个元素就是p-〉data,而p-〉next-〉data就是第i+1的元素。

(2)获取链表中第i个数据的算法思路:声明一个指针p指向链表的第一个节点,遍历链表,p不断后移,计数递增,遇到链表末尾指针为空,则说明第i个节点不存在,否则,查找成功,返回节点p的数据。

int GetElem(LinkList L,int i,ElemType *e){int j;LinkList p;p=L->next;j=1;while(p&&j<i){p=p->next;++j;}if(!p||j>i)return 0;*e=p->data;return 1;}</span>
(3)插入思想:比如说面试过程中,一个迟到的人赶来排到相应的位置,按照名单他是第i个上场的,那么第i-1个人面试完后,面试官让他叫下一个人进来,那么他就需要知道下一个人在那,如此插进来的人还要知道第i+1个人在哪,这样就完成了插入过程。

   算法思路:首先查找第i个数据的位置,如(2)所述,查找成功后,建立一个空节点s,将需要插入的新元素赋值给s->data,然后进行插入思想中标准动作,指针转移:s->next=p->next,p->next=s这个地址转移顺序不能错,为什么呢,反过来转移,p->next已经被s给覆盖了,那s->next找谁去评理


int ListInsert(ListList *L,int i,ElemType e){int j;ListList p,s;p=*L;j=1;while(p&&j<i){p=p->next;++j;}if(!p||j>i)return 0;s=(ListList)malloc(sizeof(Node));s->data=e;s->next=p->next;p->next=s;return 1;}

(4)删除思想:欲删除第i个节点,意思就是让第i-1个节点的指针p绕过第i个直接指向第i+1个节点,即p->next=p->next->next;

   删除算法:重复获取过程,查找成功后按照删除思想操作,稍作改动另设指针q=p->next;p->next=q->next,将q指针所占的空间释放掉,利用free。

int ListDelete(ListList *L,int i,ElemType *e){int j;ListList p,q;p=*L;j=1;while(p&&j<i){p=p->next;++j;}if(!p||j>i)return 0;q=p->next;p->next=q->next;*e=q->data;free(q);return 1;}
(5)创建一个空的单链表:创建空链表相当于设置一个动态的产生节点,来一个,创建一个。有两种方法,头插法和尾插法,一个始终让新节点在第一的位置,一个是始终在最后。

   创建算法:声明一个指针p和计数器变量i;初始化空链表L;让L的头结点的指针指向NULL;循环生成新节点插入过程。相比而言,尾插法更好理解,头插法声明了一个指针的指针**


//头插法
void CreatListHead(ListList *L,int n){ListList p;int i;srand(time(0));*L=(ListList)malloc(sizeof(Node));(*L)->next=NULL;for(i=0;i<n;i++){p=(ListList)malloc(sizeof(Node));p->data=rand()%100+1;p->next=(*L)->next;(*L)->next=p;}}
//尾插法
void CreatListHead(ListList *L,int n){<span style="white-space:pre"></span>ListList p,r;<span style="white-space:pre"></span>int i;<span style="white-space:pre"></span>srand(time(0));<span style="white-space:pre"></span>*L=(ListList)malloc(sizeof(Node));<span style="white-space:pre"></span>r=*L;<span style="white-space:pre"></span>for(i=0;i<n;i++)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>p=(ListList)malloc(sizeof(Node));p->data=rand()%100+1;<span style="white-space:pre"></span>r->next=p;r=p;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>r->next=NULL;}


(6)整表删除:循环释放节点空间


int ClearList(ListList *L){ListList p,q;p=(*L)->next;while(p){q=p->next;free(p);p=q;}(*L)->next=NULL;return 1;}








0 0
原创粉丝点击