一、简介
数据结构分为物理结构和逻辑结构,逻辑结构分为线性结构、几何结构、树形结构和图形结构四大结构。其中,线性表就属于线性结构。
线性表:一种逻辑结构,相同数据类型的n个数据元素的有限序列,除第一个元素外,每个元素有且仅有一个直接前驱,除最后一个元素外,每个元素有且仅有一个直接后继。
线性表的特点:
- 元素个数有限
- 逻辑上元素有先后次序
- 数据类型相同
- 仅讨论元素间的逻辑关系
二、线性表的基本操作
InitList(*L): 初始化操作,建立一个空的线性表L。
ListEmpty(L): 判断线性表是否为空表,若线性表为空,返回true,否则返回false。
ClearList(*L): 将线性表清空。
GetElem(L,i,*e): 将线性表L中的第i个位置元素值返回给e。
LocateElem(L,e): 在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中序号表示成功;否则,返回0表示失败。
ListInsert(*L,i,e): 在线性表L中第i个位置插入新元素e。
ListDelete(*L,i,*e): 删除线性表L中第i个位置元素,并用e返回其值。
ListLength(L): 返回线性表L的元素个数。
三、线性表分类
按物理结构分类:顺序存储和链式存储
1. 顺序存储
顺序表,使用数组实现,一组地址连续的存储单元,数组大小有两种方式指定,一是静态分配,二是动态扩展。
注:线性表从1开始,而数组从0开始。
优点:随机访问特性,查找O(1)时间,存储密度高;逻辑上相邻的元素,物理上也相邻;
缺点:插入删除需移动大量元素。
2. 链式存储
用一组任意的存储单元存储线性表的数据元素,这组存储单元可以存在内存中未被占用的任意位置。
也就是说,链式存储结构的线性表由一个(可以使零)或者多个结点(Node)组成。每个节点内部又分为数据域和指针域(链)。数据域存储了数据元素的信息。指针域存储了当前结点指向的直接后继的指针地址。
因为每个结点只包含一个指针域,所以叫做单链表。顾名思义,当然还有双链表。
与顺序存储相比,允许存储空间不连续,插入删除时不需要移动大量的元素,只需修改指针即可,但查找某个元素,只能从头遍历整个链表。
四、代码实现
-
C语言
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> /* 声明一个struct node的结构体类型, 包含数据域data和指向struct node变量的指针域, 利用typedef,将Node代替struct node,将PNode代替struct node* */ typedef struct node { int data; struct node* next; }Node,*PNode; //对链表操作函数的声明 PNode createList(); int lengthList(PNode); void sortList(PNode); bool insertList(PNode,int,int); bool deleteList(PNode,int,int*); void traverseList(PNode); int main() { int len = 0;//定义变量len,存放链表的长度 int val = 0;//存放链表被删除位置的值 PNode p_head = NULL; p_head = createList();//p_head指向链表的头结点 len = lengthList(p_head); printf("链表的长度: %d\n",len); printf("原始链表:\n"); traverseList(p_head);//遍历链表,依次输出 sortList(p_head);//对链表进行排序 printf("排序后的链表:\n"); traverseList(p_head); } /* 创建指定大小的链表,并对其数据域赋值, 返回头结点的地址 */ PNode createList() { int len,val;//len为链表长度,val存放数据域的值 printf("请输入元素个数:"); scanf("%d",&len); PNode p_head = (PNode)malloc(sizeof(Node));//申请一个大小为Node的动态空间,p_head指向该内存 PNode p_tail = p_head;//p_tail指向链表的最后一个元素,将头结点的地址赋值给PTail p_tail->next = NULL;//头节点的指针域置为空 PNode p_new = NULL; for(int i=0;i<len;i++) { printf("请输入元素的值:"); scanf("%d",&val); p_new = (PNode)malloc(sizeof(Node));//申请一个大小为Node的动态空间,PNew指向该内存 p_new->data = val;//将val赋值给PNew的数据域 p_tail->next = p_new;//将PNew赋值给PTail的指针域,添加到链表的最后 p_new->next=NULL; //将PNew的指针域设置为空 p_tail=p_new; //再次PTail指向链表的最后一个元素 } return p_head;//返回头结点的地址 } /* 传入头结点的地址,利用while循环遍历输出链表 */ void traverseList(PNode p_head) { PNode p = p_head->next;//将头结点的指针域赋值给p while(p!=NULL)//判断p是否为空,如果为空则跳出循环 { printf("%d\t",p->data); //输出p的数据域 p=p->next; //p指向下一个指针域 } printf("\n"); return; } /* 传入头结点的地址,利用while循环返回链表的长度 */ int lengthList(PNode p_head) { PNode p = p_head->next; int len = 0; while(p!=NULL) { len++; p = p->next; } return len; } /* 传入头结点的地址,插入位置pos和插入的值val, 先找到插入的pos位置的前一个元素的地址,然后将PNew的指针域赋值为pos-1的指针域, 将pos-1的指针域指向PNew */ bool insertList(PNode p_head,int pos,int val) { int i=0; PNode p = p_head; while(i<pos-1 && p!=NULL)//利用while循环找pos的上一个元素 { p=p->next; i++; } if(i>pos-1 || p==NULL)//插入的位置不合理,则返回false { printf("插入的位置不合理!\n"); return false; } PNode p_new = (PNode)malloc(sizeof(Node)); p_new->data = val; p_new->next = p->next; p->next = p_new; return true; } /* 传入头结点的地址,插入位置pos和变量val的地址, 先找到pos-1位置的地址,然后将该元素的指针域指向的数据赋值给*val 将pos-1的指针域被赋值为下一个元素的指针域 */ bool deleteList(PNode p_head,int pos,int* val) { int i=0; PNode p = p_head; while(i<pos-1 && p!=NULL) //找到pos位置的元素 { p=p->next; i++; } if(i>pos-1||p==NULL) { printf("删除的位置不合理!\n"); return false; } PNode q = p->next;//指针q指向的元素将被删除 *val = q->data;//将q指向的数据赋值给*val p->next = p->next->next;//将删除元素的上一个元素的指针域赋值为删除元素的下一个指针域 free(q); //释放q指向的内存 return true; } /* 传入头结点的地址,利用选择排序算法对链表进行排序 */ void sortList(PNode p_head) { PNode p,q;//定义结构指针p,q int len = lengthList(p_head);//获得链表的长度len int i,j,temp; for(i=0,p=p_head->next;i<len-1;i++,p=p->next) { for(j=i+1,q=p->next;j<len;j++,q=q->next) { if(p->data>q->data) { temp=p->data; //利用temp,将p->data与q->data的值交换 p->data=q->data; q->data=temp; } } } }
-
js语言
function LinkedList(){ var head = null; var len = 0; var Node = function(_data){ this.data = _data; this.next = null; }; this.append = function(_data){ var node = new Node(_data); var current; if(head == null){//链表为空,添加到首部 head = node; }else{ current = head; //循环链表,直到找到最后一项 while(current.next){ current = current.next; } current.next = node; } len++; }; this.removeAt = function(_pos){ if(_pos>-1 && pos<len){ var current = head; var previous; var index = 0; if(_pos==0){ head = current.next;//移除第一个元素,直接把head指向下一个元素 }else{ while(index++ < _pos){ previous = current; current = current.next; } //跳过current,将当前要移除的元素的上一个与下一项直接连接起来。 previous.next = current.next; } current = null; len--; return true; }else{ return false; } }; this.insert = function(_pos,_val){ if(_pos >= 0 && _pos <= len){ var node = new Node(_val) var current = head; var previous; var index=0; if(_pos === 0){//第一个位置 node.next = current; head = node; }else{ while (index++ < _pos ) { //循环迭代到目标位置 previous = current; current = current.next; } node.next = current; // node的下一个为current previous.next = node; // node的上一个位置为previous } len++; return true; }else{ return false; } }; this.toString = function(){ var current = head; var string = ''; while(current){ string += current.data + (current.next ? '\n' : ''); current = current.next; } return string; }; this.find = function(_val){ var current = head; var index = 0; while(current){ if(_val === current.data){ return index; } index++; current = current.next; } return -1; }; this.remove = function(_val){ var index = this.find(_val); return this.removeAt(index); }; this.length = function(){ return len }; } var list = new LinkedList() list.append(5) list.append(52) alert(list.toString())