上一篇介紹了線性表的順序存儲結構,順序存儲結構的最大缺點就是插入和刪除時需要移除大量元素,如果要插入或刪除的數據量很大的話,執行程序的時間就會很長,造成一定的性能消耗,且線性表的順序存儲結構如動態數組,棧和隊列,底層依託靜態數組,需要通過擴容解決固定容量問題。由於順序結構的以上問題,鏈表的優勢就凸顯出來,鏈表是最簡單的動態數據結構,不需要處理固定容量問題,且插入和刪除元素,不需要移動其他元素,所以對於大數據量的頻繁插入和刪除操作,使用鏈表的優勢就很明顯,但鏈表也喪失了隨機訪問的能力,所以對於大數據量的頻繁查詢操作使用順序存儲結構比較好。
C語言代碼:
1.LinkedList.c
typedef int ElemType;
typedef int Status;
#include <stdlib.h>
#include <stdio.h>
#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
/**
* 線性表的單鏈表存儲結構
*/
typedef struct Node{
ElemType data; //數據域
struct Node *next; //指針域
}Node,*LinkedList;
/**
* 創建帶頭結點的單鏈表
* 使用頭插法:始終將新節點插入到表頭
* @param L
*/
void CreateListHead(LinkedList *L){
LinkedList p;
*L =(LinkedList) malloc(sizeof(Node));
(*L)->next = NULL; //建立一個帶頭結點的單鏈表
for (int i = 0; i < 10; ++i) {
p =(LinkedList) malloc(sizeof(Node)); //生成新的節點
p->data = i;
p->next = (*L)->next;
(*L)->next = p; //插入到表頭
}
}
/**
* 創建帶頭結點的單鏈表
* 使用尾插法:始終將新節點插入到表尾
* @param L
*/
void CreateListTail(LinkedList *L){
LinkedList p,r;
int i;
*L =(LinkedList) malloc(sizeof(Node));
r = *L; //r爲指向尾部的節點
for (int i = 0; i < 10; ++i) {
p =(LinkedList) malloc(sizeof(Node));
p->data = i;
r->next = p; //將線性表表尾的節點指向新的節點
r = p; //將新插入的節點定義爲表尾節點
}
r->next = NULL; //當前鏈表結束,最後一個節點的指針置爲空
}
/**
* 遍歷打印鏈表元素
* @param L
*/
void Display(LinkedList L){
LinkedList p = L->next; //將第一個節點賦值給臨時節點p
printf("鏈表的元素爲:");
if(!p)
printf("鏈表爲空");
while (p){
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
/**
* 獲取鏈表的長度
* @param L
* @return
*/
int GetLinkedListSize(LinkedList L){
int len = 0;
LinkedList p = L->next;
while (p){
len++;
p = p->next;
}
return len;
}
/**
* 判斷鏈表是否爲空
* @param L
* @return
*/
int IsLinkedListEmpty(LinkedList L){
LinkedList p = L->next;
if(!p)
return TRUE;
return FALSE;
}
/**
* 查詢單鏈表,並用e返回L中第i個位置元素的值
* @param L
* @param i
* @param e
* @return
*/
Status GetElement(LinkedList L,int i,ElemType *e){
int j;
LinkedList p;
p = L->next; //p指向鏈表的第一個節點
j = 1;
while (p && j<i){
p = p->next;
j++;
}
if(!p || j>i)
return ERROR; //第i個節點不存在
*e = p->data;
return OK;
}
/**
* 給單鏈表插入元素,在L中第I個元素之前插入新的元素e
* @param L
* @param i
* @param e
* @return
*/
Status LinkedListInsert(LinkedList *L,int i,ElemType e){
int j;
LinkedList p,s;
p = *L;
j = 1;
while (p && j<i){ //找到第i-1個節點
p = p->next;
j++;
}
if(!p || j>i)
return ERROR; //第i個節點不存在
s =(LinkedList) malloc(sizeof(Node));
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
/**
* 刪除單鏈表L的第i個節點,並用e返回其值
* @param L
* @param i
* @param e
* @return
*/
Status LinkedListDelete(LinkedList *L,int i,ElemType *e){
int j;
LinkedList p,q;
p = *L;
j = 1;
while (p->next && j<i){ //找到第i-1個節點
p = p->next;
j++;
}
if(!(p->next) || j>i)
return ERROR; //第i個節點不存在
q = p->next;
p->next = q->next;
*e = q->data;
free(q); //讓系統回收此節點,釋放內存
return OK;
}
/**
* 刪除整個鏈表
* @param L
* @return
*/
Status ClearLinkedList(LinkedList *L){
LinkedList p,q;
p = (*L)->next; //p指向第一個節點
while (p){
q = p->next;
free(p);
p = q;
}
(*L)->next = NULL; //將頭結點的指針域置爲空
return OK;
}
2.LinkedList.h
typedef int ElemType;
typedef int Status;
#include <stdlib.h>
#include <stdio.h>
#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
/**
* 線性表的單鏈表存儲結構
*/
typedef struct Node{
ElemType data; //數據域
struct Node *next; //指針域
}Node,*LinkedList;
//創建帶頭結點的單鏈表(頭插法)
void CreateListHead(LinkedList *L);
//創建帶頭結點的單鏈表(尾插法)
void CreateListTail(LinkedList *L);
//遍歷打印鏈表元素
void Display(LinkedList L);
//獲取鏈表長度
int GetLinkedListSize(LinkedList L);
//判斷鏈表是否爲空
int IsLinkedListEmpty(LinkedList L);
// 查詢單鏈表,並用e返回L中第i個位置元素的值
Status GetElement(LinkedList L,int i,ElemType *e);
//給單鏈表插入元素,在L中第I個元素之前插入新的元素e
Status LinkedListInsert(LinkedList *L,int i,ElemType e);
//刪除單鏈表L的第i個節點,並用e返回其值
Status LinkedListDelete(LinkedList *L,int i,ElemType *e);
//刪除整個鏈表
Status ClearLinkedList(LinkedList *L);
3.main.c
//初始化一個具有10個元素的鏈表(頭插法)
LinkedList list;
CreateListHead(&list);
Display(list);
//初始化一個具有10個元素的鏈表(尾插法)
CreateListTail(&list);
Display(list);
//獲取鏈表長度
int len = GetLinkedListSize(list);
printf("%d",len);
printf("\n");
//判斷鏈表是否爲空
int result = IsLinkedListEmpty(list);
printf("%d",result);
printf("\n");
//查詢鏈表某個位置的元素
int num;
int *n = #
GetElement(list,6,n);
printf("%d",*n);
printf("\n");
//插入元素
LinkedListInsert(&list,3,16);
Display(list);
//刪除元素
int delNum;
int *d = &delNum;
LinkedListDelete(&list,3,d);
Display(list);
printf("%d",*d);
printf("\n");
//刪除整個鏈表
ClearLinkedList(&list);
Display(list);
int result2 = IsLinkedListEmpty(list);
printf("%d",result2);
4.執行結果
鏈表的元素爲:9 8 7 6 5 4 3 2 1 0
鏈表的元素爲:0 1 2 3 4 5 6 7 8 9
10
0
5
鏈表的元素爲:0 1 16 2 3 4 5 6 7 8 9
鏈表的元素爲:0 1 2 3 4 5 6 7 8 9
16
鏈表的元素爲:鏈表爲空
1
java代碼:
public class LinkedList<E> {
private class Node{
public E e;
public Node next;
public Node(E e,Node next){
this.e = e;
this.next = next;
}
public Node(E e){
this(e,null);
}
public Node(){
this(null,null);
}
@Override
public String toString() {
return e.toString();
}
}
private Node dummyHead; //鏈表頭結點
private int size;
public LinkedList(){
this.dummyHead = new Node(null,null);
this.size= 0;
}
//獲取鏈表中元素的個數
public int getSize(){
return size;
}
//鏈表是否爲空
public boolean isEmpty(){
return size == 0;
}
//在鏈表指定的位置添加元素
public void add(int index,E e){ //鏈表實際上是沒有索引的概念的,爲了便於理解起見,這裏引入索引概念,這裏索引從0開始,和C語言版的鏈表區分
if(index < 0 || index > size){
throw new IllegalArgumentException("非法索引");
}
Node prev = dummyHead;
for (int i = 0; i < index ; i++) {
prev = prev.next;
}
/* Node node = new Node(e);
node.next = prev.next;
prev.next = node;*/
prev.next = new Node(e,prev.next); //此處的代碼執行效果等價於上面註釋掉的代碼
size++;
}
//在鏈表頭添加新的元素
public void addFirst(E e){
//1
/* Node node = new Node(e); //1和2的執行效果等價
node.next = head;100
head = node;
*/
// 2 head = new Node(e,head);
add(0,e);
}
//在鏈表的末尾添加新的元素
public void addLast(E e){
add(size,e);
}
//獲取鏈表指定位置元素
public E get(int index){
if(index < 0 || index >= size){
throw new IllegalArgumentException("非法索引");
}
Node cur = dummyHead.next;
for (int i = 0; i < index ; i++) {
cur = cur.next;
}
return cur.e;
}
//獲取鏈表的第一個元素
public E getFirst(){
return get(0);
}
//獲取鏈表的最後一個元素
public E getLast(){
return get(size-1);
}
//修改鏈表指定位置的元素值
public void set(int index,E e){
if(index < 0 || index >= size){
throw new IllegalArgumentException("非法索引");
}
Node cur = dummyHead.next;
for (int i = 0; i < index ; i++) {
cur = cur.next;
}
cur.e = e;
}
//查找鏈表是否有元素e
public boolean contains(E e){
Node cur = dummyHead.next;
while (cur != null){
if(cur.e.equals(e)){
return true;
}
cur = cur.next;
}
return false;
}
//刪除指定位置的鏈表元素
public E remove(int index){
if(index < 0 || index >= size){
throw new IllegalArgumentException("非法索引");
}
Node prev = dummyHead;
for (int i = 0; i < index; i++) { //找到要刪除節點的前一個節點
prev = prev.next;
}
Node retNode = prev.next;
prev.next = prev.next.next;
retNode.next = null;
size--;
return retNode.e;
}
//刪除鏈表的第一個元素
public E removeFirst(){
return remove(0);
}
//刪除鏈表的最後一個元素
public E removeLast(){
return remove(size-1);
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
Node cur = dummyHead.next;
while (cur != null){
res.append(cur + "->");
cur = cur.next;
}
res.append("NULL");
return res.toString();
}
public static void main(String[] args) {
LinkedList<Integer> linkedList = new LinkedList<>();
for (int i = 0; i < 5; i++) {
linkedList.addFirst(i);
System.out.println(linkedList);
}
linkedList.add(0,521);
System.out.println(linkedList);
linkedList.add(3,521);
System.out.println(linkedList);
int num = linkedList.get(2);
System.out.println(num);
linkedList.remove(3);
System.out.println(linkedList);
linkedList.removeFirst();
System.out.println(linkedList);
}
}
微信公衆號: